1package miniredis
2
3import (
4	"sort"
5	"testing"
6
7	"github.com/gomodule/redigo/redis"
8)
9
10// Test SADD / SMEMBERS.
11func TestSadd(t *testing.T) {
12	s, err := Run()
13	ok(t, err)
14	defer s.Close()
15	c, err := redis.Dial("tcp", s.Addr())
16	ok(t, err)
17
18	{
19		b, err := redis.Int(c.Do("SADD", "s", "aap", "noot", "mies"))
20		ok(t, err)
21		equals(t, 3, b) // New elements.
22
23		members, err := s.Members("s")
24		ok(t, err)
25		equals(t, []string{"aap", "mies", "noot"}, members)
26
27		m, err := redis.Strings(c.Do("SMEMBERS", "s"))
28		ok(t, err)
29		equals(t, []string{"aap", "mies", "noot"}, m)
30	}
31
32	{
33		b, err := redis.String(c.Do("TYPE", "s"))
34		ok(t, err)
35		equals(t, "set", b)
36	}
37
38	// SMEMBERS on an nonexisting key
39	{
40		m, err := redis.Strings(c.Do("SMEMBERS", "nosuch"))
41		ok(t, err)
42		equals(t, []string{}, m)
43	}
44
45	{
46		b, err := redis.Int(c.Do("SADD", "s", "new", "noot", "mies"))
47		ok(t, err)
48		equals(t, 1, b) // Only one new field.
49
50		members, err := s.Members("s")
51		ok(t, err)
52		equals(t, []string{"aap", "mies", "new", "noot"}, members)
53	}
54
55	// Direct usage
56	{
57		added, err := s.SetAdd("s1", "aap")
58		ok(t, err)
59		equals(t, 1, added)
60
61		members, err := s.Members("s1")
62		ok(t, err)
63		equals(t, []string{"aap"}, members)
64	}
65
66	// Wrong type of key
67	{
68		_, err := redis.String(c.Do("SET", "str", "value"))
69		ok(t, err)
70		_, err = redis.Int(c.Do("SADD", "str", "hi"))
71		assert(t, err != nil, "SADD error")
72		_, err = redis.Int(c.Do("SMEMBERS", "str"))
73		assert(t, err != nil, "MEMBERS error")
74		// Wrong argument counts
75		_, err = redis.String(c.Do("SADD"))
76		assert(t, err != nil, "SADD error")
77		_, err = redis.String(c.Do("SADD", "set"))
78		assert(t, err != nil, "SADD error")
79		_, err = redis.String(c.Do("SMEMBERS"))
80		assert(t, err != nil, "SMEMBERS error")
81		_, err = redis.String(c.Do("SMEMBERS", "set", "spurious"))
82		assert(t, err != nil, "SMEMBERS error")
83	}
84
85}
86
87// Test SISMEMBER
88func TestSismember(t *testing.T) {
89	s, err := Run()
90	ok(t, err)
91	defer s.Close()
92	c, err := redis.Dial("tcp", s.Addr())
93	ok(t, err)
94
95	s.SetAdd("s", "aap", "noot", "mies")
96
97	{
98		b, err := redis.Int(c.Do("SISMEMBER", "s", "aap"))
99		ok(t, err)
100		equals(t, 1, b)
101
102		b, err = redis.Int(c.Do("SISMEMBER", "s", "nosuch"))
103		ok(t, err)
104		equals(t, 0, b)
105	}
106
107	// a nonexisting key
108	{
109		b, err := redis.Int(c.Do("SISMEMBER", "nosuch", "nosuch"))
110		ok(t, err)
111		equals(t, 0, b)
112	}
113
114	// Direct usage
115	{
116		isMember, err := s.IsMember("s", "noot")
117		ok(t, err)
118		equals(t, true, isMember)
119	}
120
121	// Wrong type of key
122	{
123		_, err := redis.String(c.Do("SET", "str", "value"))
124		ok(t, err)
125		_, err = redis.Int(c.Do("SISMEMBER", "str"))
126		assert(t, err != nil, "SISMEMBER error")
127		// Wrong argument counts
128		_, err = redis.String(c.Do("SISMEMBER"))
129		assert(t, err != nil, "SISMEMBER error")
130		_, err = redis.String(c.Do("SISMEMBER", "set"))
131		assert(t, err != nil, "SISMEMBER error")
132		_, err = redis.String(c.Do("SISMEMBER", "set", "spurious", "args"))
133		assert(t, err != nil, "SISMEMBER error")
134	}
135
136}
137
138// Test SREM
139func TestSrem(t *testing.T) {
140	s, err := Run()
141	ok(t, err)
142	defer s.Close()
143	c, err := redis.Dial("tcp", s.Addr())
144	ok(t, err)
145
146	s.SetAdd("s", "aap", "noot", "mies", "vuur")
147
148	{
149		b, err := redis.Int(c.Do("SREM", "s", "aap", "noot"))
150		ok(t, err)
151		equals(t, 2, b)
152
153		members, err := s.Members("s")
154		ok(t, err)
155		equals(t, []string{"mies", "vuur"}, members)
156	}
157
158	// a nonexisting field
159	{
160		b, err := redis.Int(c.Do("SREM", "s", "nosuch"))
161		ok(t, err)
162		equals(t, 0, b)
163	}
164
165	// a nonexisting key
166	{
167		b, err := redis.Int(c.Do("SREM", "nosuch", "nosuch"))
168		ok(t, err)
169		equals(t, 0, b)
170	}
171
172	// Direct usage
173	{
174		b, err := s.SRem("s", "mies")
175		ok(t, err)
176		equals(t, 1, b)
177
178		members, err := s.Members("s")
179		ok(t, err)
180		equals(t, []string{"vuur"}, members)
181	}
182
183	// Wrong type of key
184	{
185		_, err := redis.String(c.Do("SET", "str", "value"))
186		ok(t, err)
187		_, err = redis.Int(c.Do("SREM", "str", "value"))
188		assert(t, err != nil, "SREM error")
189		// Wrong argument counts
190		_, err = redis.String(c.Do("SREM"))
191		assert(t, err != nil, "SREM error")
192		_, err = redis.String(c.Do("SREM", "set"))
193		assert(t, err != nil, "SREM error")
194		_, err = redis.String(c.Do("SREM", "set", "spurious", "args"))
195		assert(t, err != nil, "SREM error")
196	}
197}
198
199// Test SMOVE
200func TestSmove(t *testing.T) {
201	s, err := Run()
202	ok(t, err)
203	defer s.Close()
204	c, err := redis.Dial("tcp", s.Addr())
205	ok(t, err)
206
207	s.SetAdd("s", "aap", "noot")
208
209	{
210		b, err := redis.Int(c.Do("SMOVE", "s", "s2", "aap"))
211		ok(t, err)
212		equals(t, 1, b)
213
214		m, err := s.IsMember("s", "aap")
215		ok(t, err)
216		equals(t, false, m)
217		m, err = s.IsMember("s2", "aap")
218		ok(t, err)
219		equals(t, true, m)
220	}
221
222	// Move away the last member
223	{
224		b, err := redis.Int(c.Do("SMOVE", "s", "s2", "noot"))
225		ok(t, err)
226		equals(t, 1, b)
227
228		equals(t, false, s.Exists("s"))
229
230		m, err := s.IsMember("s2", "noot")
231		ok(t, err)
232		equals(t, true, m)
233	}
234
235	// a nonexisting member
236	{
237		b, err := redis.Int(c.Do("SMOVE", "s", "s2", "nosuch"))
238		ok(t, err)
239		equals(t, 0, b)
240	}
241
242	// a nonexisting key
243	{
244		b, err := redis.Int(c.Do("SMOVE", "nosuch", "nosuch2", "nosuch"))
245		ok(t, err)
246		equals(t, 0, b)
247	}
248
249	// Wrong type of key
250	{
251		_, err := redis.String(c.Do("SET", "str", "value"))
252		ok(t, err)
253		_, err = redis.Int(c.Do("SMOVE", "str", "dst", "value"))
254		assert(t, err != nil, "SMOVE error")
255		_, err = redis.Int(c.Do("SMOVE", "s2", "str", "value"))
256		assert(t, err != nil, "SMOVE error")
257		// Wrong argument counts
258		_, err = redis.String(c.Do("SMOVE"))
259		assert(t, err != nil, "SMOVE error")
260		_, err = redis.String(c.Do("SMOVE", "set"))
261		assert(t, err != nil, "SMOVE error")
262		_, err = redis.String(c.Do("SMOVE", "set", "set2"))
263		assert(t, err != nil, "SMOVE error")
264		_, err = redis.String(c.Do("SMOVE", "set", "set2", "spurious", "args"))
265		assert(t, err != nil, "SMOVE error")
266	}
267}
268
269// Test SPOP
270func TestSpop(t *testing.T) {
271	s, err := Run()
272	ok(t, err)
273	defer s.Close()
274	c, err := redis.Dial("tcp", s.Addr())
275	ok(t, err)
276
277	s.SetAdd("s", "aap", "noot")
278
279	{
280		el, err := redis.String(c.Do("SPOP", "s"))
281		ok(t, err)
282		assert(t, el == "aap" || el == "noot", "spop got something")
283
284		el, err = redis.String(c.Do("SPOP", "s"))
285		ok(t, err)
286		assert(t, el == "aap" || el == "noot", "spop got something")
287
288		assert(t, !s.Exists("s"), "all spopped away")
289	}
290
291	// a nonexisting key
292	{
293		b, err := c.Do("SPOP", "nosuch")
294		ok(t, err)
295		equals(t, nil, b)
296	}
297
298	// various errors
299	{
300		s.SetAdd("chk", "aap", "noot")
301		s.Set("str", "value")
302
303		_, err = redis.String(c.Do("SMOVE"))
304		assert(t, err != nil, "SMOVE error")
305		_, err = redis.String(c.Do("SMOVE", "chk", "set2"))
306		assert(t, err != nil, "SMOVE error")
307
308		_, err = c.Do("SPOP", "str")
309		assert(t, err != nil, "SPOP error")
310	}
311
312	// count argument
313	{
314		s.SetAdd("s", "aap", "noot", "mies", "vuur")
315		el, err := redis.Strings(c.Do("SPOP", "s", 2))
316		ok(t, err)
317		assert(t, len(el) == 2, "SPOP s 2")
318		members, err := s.Members("s")
319		ok(t, err)
320		assert(t, len(members) == 2, "SPOP s 2")
321	}
322}
323
324// Test SRANDMEMBER
325func TestSrandmember(t *testing.T) {
326	s, err := Run()
327	ok(t, err)
328	defer s.Close()
329	c, err := redis.Dial("tcp", s.Addr())
330	ok(t, err)
331
332	s.SetAdd("s", "aap", "noot", "mies")
333
334	// No count
335	{
336		el, err := redis.String(c.Do("SRANDMEMBER", "s"))
337		ok(t, err)
338		assert(t, el == "aap" || el == "noot" || el == "mies", "srandmember got something")
339	}
340
341	// Positive count
342	{
343		els, err := redis.Strings(c.Do("SRANDMEMBER", "s", 2))
344		ok(t, err)
345		equals(t, 2, len(els))
346	}
347
348	// Negative count
349	{
350		els, err := redis.Strings(c.Do("SRANDMEMBER", "s", -2))
351		ok(t, err)
352		equals(t, 2, len(els))
353	}
354
355	// a nonexisting key
356	{
357		b, err := c.Do("SRANDMEMBER", "nosuch")
358		ok(t, err)
359		equals(t, nil, b)
360	}
361
362	// Various errors
363	{
364		s.SetAdd("chk", "aap", "noot")
365		s.Set("str", "value")
366
367		_, err = redis.String(c.Do("SRANDMEMBER"))
368		assert(t, err != nil, "SRANDMEMBER error")
369		_, err = redis.String(c.Do("SRANDMEMBER", "chk", "noint"))
370		assert(t, err != nil, "SRANDMEMBER error")
371		_, err = redis.String(c.Do("SRANDMEMBER", "chk", 1, "toomanu"))
372		assert(t, err != nil, "SRANDMEMBER error")
373
374		_, err = c.Do("SRANDMEMBER", "str")
375		assert(t, err != nil, "SRANDMEMBER error")
376	}
377}
378
379// Test SDIFF
380func TestSdiff(t *testing.T) {
381	s, err := Run()
382	ok(t, err)
383	defer s.Close()
384	c, err := redis.Dial("tcp", s.Addr())
385	ok(t, err)
386
387	s.SetAdd("s1", "aap", "noot", "mies")
388	s.SetAdd("s2", "noot", "mies", "vuur")
389	s.SetAdd("s3", "aap", "mies", "wim")
390
391	// Simple case
392	{
393		els, err := redis.Strings(c.Do("SDIFF", "s1", "s2"))
394		ok(t, err)
395		equals(t, []string{"aap"}, els)
396	}
397
398	// No other set
399	{
400		els, err := redis.Strings(c.Do("SDIFF", "s1"))
401		ok(t, err)
402		sort.Strings(els)
403		equals(t, []string{"aap", "mies", "noot"}, els)
404	}
405
406	// 3 sets
407	{
408		els, err := redis.Strings(c.Do("SDIFF", "s1", "s2", "s3"))
409		ok(t, err)
410		equals(t, []string{}, els)
411	}
412
413	// A nonexisting key
414	{
415		els, err := redis.Strings(c.Do("SDIFF", "s9"))
416		ok(t, err)
417		equals(t, []string{}, els)
418	}
419
420	// Various errors
421	{
422		s.SetAdd("chk", "aap", "noot")
423		s.Set("str", "value")
424
425		_, err = redis.String(c.Do("SDIFF"))
426		assert(t, err != nil, "SDIFF error")
427		_, err = redis.String(c.Do("SDIFF", "str"))
428		assert(t, err != nil, "SDIFF error")
429		_, err = redis.String(c.Do("SDIFF", "chk", "str"))
430		assert(t, err != nil, "SDIFF error")
431	}
432}
433
434// Test SDIFFSTORE
435func TestSdiffstore(t *testing.T) {
436	s, err := Run()
437	ok(t, err)
438	defer s.Close()
439	c, err := redis.Dial("tcp", s.Addr())
440	ok(t, err)
441
442	s.SetAdd("s1", "aap", "noot", "mies")
443	s.SetAdd("s2", "noot", "mies", "vuur")
444	s.SetAdd("s3", "aap", "mies", "wim")
445
446	// Simple case
447	{
448		i, err := redis.Int(c.Do("SDIFFSTORE", "res", "s1", "s3"))
449		ok(t, err)
450		equals(t, 1, i)
451		s.CheckSet(t, "res", "noot")
452	}
453
454	// Various errors
455	{
456		s.SetAdd("chk", "aap", "noot")
457		s.Set("str", "value")
458
459		_, err = redis.String(c.Do("SDIFFSTORE"))
460		assert(t, err != nil, "SDIFFSTORE error")
461		_, err = redis.String(c.Do("SDIFFSTORE", "t"))
462		assert(t, err != nil, "SDIFFSTORE error")
463		_, err = redis.String(c.Do("SDIFFSTORE", "t", "str"))
464		assert(t, err != nil, "SDIFFSTORE error")
465	}
466}
467
468// Test SINTER
469func TestSinter(t *testing.T) {
470	s, err := Run()
471	ok(t, err)
472	defer s.Close()
473	c, err := redis.Dial("tcp", s.Addr())
474	ok(t, err)
475
476	s.SetAdd("s1", "aap", "noot", "mies")
477	s.SetAdd("s2", "noot", "mies", "vuur")
478	s.SetAdd("s3", "aap", "mies", "wim")
479
480	// Simple case
481	{
482		els, err := redis.Strings(c.Do("SINTER", "s1", "s2"))
483		ok(t, err)
484		sort.Strings(els)
485		equals(t, []string{"mies", "noot"}, els)
486	}
487
488	// No other set
489	{
490		els, err := redis.Strings(c.Do("SINTER", "s1"))
491		ok(t, err)
492		sort.Strings(els)
493		equals(t, []string{"aap", "mies", "noot"}, els)
494	}
495
496	// 3 sets
497	{
498		els, err := redis.Strings(c.Do("SINTER", "s1", "s2", "s3"))
499		ok(t, err)
500		equals(t, []string{"mies"}, els)
501	}
502
503	// A nonexisting key
504	{
505		els, err := redis.Strings(c.Do("SINTER", "s9"))
506		ok(t, err)
507		equals(t, []string{}, els)
508	}
509
510	// With one of the keys being an empty set, the resulting set is also empty
511	{
512		els, err := redis.Strings(c.Do("SINTER", "s1", "s9"))
513		ok(t, err)
514		equals(t, []string{}, els)
515	}
516
517	// Various errors
518	{
519		s.SetAdd("chk", "aap", "noot")
520		s.Set("str", "value")
521
522		_, err = redis.String(c.Do("SINTER"))
523		assert(t, err != nil, "SINTER error")
524		_, err = redis.String(c.Do("SINTER", "str"))
525		assert(t, err != nil, "SINTER error")
526		_, err = redis.String(c.Do("SINTER", "chk", "str"))
527		assert(t, err != nil, "SINTER error")
528	}
529}
530
531// Test SINTERSTORE
532func TestSinterstore(t *testing.T) {
533	s, err := Run()
534	ok(t, err)
535	defer s.Close()
536	c, err := redis.Dial("tcp", s.Addr())
537	ok(t, err)
538
539	s.SetAdd("s1", "aap", "noot", "mies")
540	s.SetAdd("s2", "noot", "mies", "vuur")
541	s.SetAdd("s3", "aap", "mies", "wim")
542
543	// Simple case
544	{
545		i, err := redis.Int(c.Do("SINTERSTORE", "res", "s1", "s3"))
546		ok(t, err)
547		equals(t, 2, i)
548		s.CheckSet(t, "res", "aap", "mies")
549	}
550
551	// With one of the keys being an empty set, the resulting set is also empty
552	{
553		i, err := redis.Int(c.Do("SINTERSTORE", "res", "s1", "s9"))
554		ok(t, err)
555		equals(t, 0, i)
556		s.CheckSet(t, "res", []string{}...)
557	}
558
559	// Various errors
560	{
561		s.SetAdd("chk", "aap", "noot")
562		s.Set("str", "value")
563
564		_, err = redis.String(c.Do("SINTERSTORE"))
565		assert(t, err != nil, "SINTERSTORE error")
566		_, err = redis.String(c.Do("SINTERSTORE", "t"))
567		assert(t, err != nil, "SINTERSTORE error")
568		_, err = redis.String(c.Do("SINTERSTORE", "t", "str"))
569		assert(t, err != nil, "SINTERSTORE error")
570	}
571}
572
573// Test SUNION
574func TestSunion(t *testing.T) {
575	s, err := Run()
576	ok(t, err)
577	defer s.Close()
578	c, err := redis.Dial("tcp", s.Addr())
579	ok(t, err)
580
581	s.SetAdd("s1", "aap", "noot", "mies")
582	s.SetAdd("s2", "noot", "mies", "vuur")
583	s.SetAdd("s3", "aap", "mies", "wim")
584
585	// Simple case
586	{
587		els, err := redis.Strings(c.Do("SUNION", "s1", "s2"))
588		ok(t, err)
589		sort.Strings(els)
590		equals(t, []string{"aap", "mies", "noot", "vuur"}, els)
591	}
592
593	// No other set
594	{
595		els, err := redis.Strings(c.Do("SUNION", "s1"))
596		ok(t, err)
597		sort.Strings(els)
598		equals(t, []string{"aap", "mies", "noot"}, els)
599	}
600
601	// 3 sets
602	{
603		els, err := redis.Strings(c.Do("SUNION", "s1", "s2", "s3"))
604		ok(t, err)
605		sort.Strings(els)
606		equals(t, []string{"aap", "mies", "noot", "vuur", "wim"}, els)
607	}
608
609	// A nonexisting key
610	{
611		els, err := redis.Strings(c.Do("SUNION", "s9"))
612		ok(t, err)
613		equals(t, []string{}, els)
614	}
615
616	// Various errors
617	{
618		s.SetAdd("chk", "aap", "noot")
619		s.Set("str", "value")
620
621		_, err = redis.String(c.Do("SUNION"))
622		assert(t, err != nil, "SUNION error")
623		_, err = redis.String(c.Do("SUNION", "str"))
624		assert(t, err != nil, "SUNION error")
625		_, err = redis.String(c.Do("SUNION", "chk", "str"))
626		assert(t, err != nil, "SUNION error")
627	}
628}
629
630// Test SUNIONSTORE
631func TestSunionstore(t *testing.T) {
632	s, err := Run()
633	ok(t, err)
634	defer s.Close()
635	c, err := redis.Dial("tcp", s.Addr())
636	ok(t, err)
637
638	s.SetAdd("s1", "aap", "noot", "mies")
639	s.SetAdd("s2", "noot", "mies", "vuur")
640	s.SetAdd("s3", "aap", "mies", "wim")
641
642	// Simple case
643	{
644		i, err := redis.Int(c.Do("SUNIONSTORE", "res", "s1", "s3"))
645		ok(t, err)
646		equals(t, 4, i)
647		s.CheckSet(t, "res", "aap", "mies", "noot", "wim")
648	}
649
650	// Various errors
651	{
652		s.SetAdd("chk", "aap", "noot")
653		s.Set("str", "value")
654
655		_, err = redis.String(c.Do("SUNIONSTORE"))
656		assert(t, err != nil, "SUNIONSTORE error")
657		_, err = redis.String(c.Do("SUNIONSTORE", "t"))
658		assert(t, err != nil, "SUNIONSTORE error")
659		_, err = redis.String(c.Do("SUNIONSTORE", "t", "str"))
660		assert(t, err != nil, "SUNIONSTORE error")
661	}
662}
663
664func TestSscan(t *testing.T) {
665	s, err := Run()
666	ok(t, err)
667	defer s.Close()
668	c, err := redis.Dial("tcp", s.Addr())
669	ok(t, err)
670
671	// We cheat with sscan. It always returns everything.
672
673	s.SetAdd("set", "value1", "value2")
674
675	// No problem
676	{
677		res, err := redis.Values(c.Do("SSCAN", "set", 0))
678		ok(t, err)
679		equals(t, 2, len(res))
680
681		var c int
682		var keys []string
683		_, err = redis.Scan(res, &c, &keys)
684		ok(t, err)
685		equals(t, 0, c)
686		equals(t, []string{"value1", "value2"}, keys)
687	}
688
689	// Invalid cursor
690	{
691		res, err := redis.Values(c.Do("SSCAN", "set", 42))
692		ok(t, err)
693		equals(t, 2, len(res))
694
695		var c int
696		var keys []string
697		_, err = redis.Scan(res, &c, &keys)
698		ok(t, err)
699		equals(t, 0, c)
700		equals(t, []string(nil), keys)
701	}
702
703	// COUNT (ignored)
704	{
705		res, err := redis.Values(c.Do("SSCAN", "set", 0, "COUNT", 200))
706		ok(t, err)
707		equals(t, 2, len(res))
708
709		var c int
710		var keys []string
711		_, err = redis.Scan(res, &c, &keys)
712		ok(t, err)
713		equals(t, 0, c)
714		equals(t, []string{"value1", "value2"}, keys)
715	}
716
717	// MATCH
718	{
719		s.SetAdd("set", "aap", "noot", "mies")
720		res, err := redis.Values(c.Do("SSCAN", "set", 0, "MATCH", "mi*"))
721		ok(t, err)
722		equals(t, 2, len(res))
723
724		var c int
725		var keys []string
726		_, err = redis.Scan(res, &c, &keys)
727		ok(t, err)
728		equals(t, 0, c)
729		equals(t, []string{"mies"}, keys)
730	}
731
732	// Wrong usage
733	{
734		_, err := redis.Int(c.Do("SSCAN"))
735		assert(t, err != nil, "do SSCAN error")
736		_, err = redis.Int(c.Do("SSCAN", "set"))
737		assert(t, err != nil, "do SSCAN error")
738		_, err = redis.Int(c.Do("SSCAN", "set", "noint"))
739		assert(t, err != nil, "do SSCAN error")
740		_, err = redis.Int(c.Do("SSCAN", "set", 1, "MATCH"))
741		assert(t, err != nil, "do SSCAN error")
742		_, err = redis.Int(c.Do("SSCAN", "set", 1, "COUNT"))
743		assert(t, err != nil, "do SSCAN error")
744		_, err = redis.Int(c.Do("SSCAN", "set", 1, "COUNT", "noint"))
745		assert(t, err != nil, "do SSCAN error")
746		s.Set("str", "value")
747		_, err = redis.Int(c.Do("SSCAN", "str", 1))
748		assert(t, err != nil, "do SSCAN error")
749	}
750}
751