redis-objects 1.4.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/redis/value.rb CHANGED
@@ -6,11 +6,6 @@ class Redis
6
6
  # Class representing a simple value. You can use standard Ruby operations on it.
7
7
  #
8
8
  class Value < BaseObject
9
- require 'redis/helpers/core_commands'
10
- include Redis::Helpers::CoreCommands
11
-
12
- attr_reader :key, :options
13
-
14
9
  def value=(val)
15
10
  allow_expiration do
16
11
  if val.nil?
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  # Only fix this one version or else tests break
22
- spec.add_dependency "redis", "~> 4.0"
22
+ spec.add_dependency "redis", "< 4.6"
23
23
 
24
24
  # Ignore gemspec warnings on these. Trying to fix them to versions breaks TravisCI
25
25
  spec.add_development_dependency "bundler"
@@ -29,6 +29,10 @@ Gem::Specification.new do |spec|
29
29
 
30
30
  # Compatibility testing
31
31
  spec.add_development_dependency "redis-namespace"
32
+ spec.add_development_dependency "activesupport"
32
33
  spec.add_development_dependency "activerecord"
33
34
  spec.add_development_dependency "sqlite3"
35
+
36
+ # Code coverage
37
+ spec.add_development_dependency "simplecov-cobertura"
34
38
  end
@@ -4,7 +4,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
4
4
  # tests whether autoload functionality works correctly; had issues previously
5
5
 
6
6
  require 'redis/objects'
7
- # $redis used automatically
7
+ Redis::Objects.redis = REDIS_HANDLE
8
8
 
9
9
  describe 'Redis::Objects' do
10
10
  it "should autoload everything" do
@@ -5,6 +5,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
5
5
 
6
6
  require 'redis/objects'
7
7
  require 'connection_pool'
8
+ Redis::Objects.redis = REDIS_HANDLE
8
9
 
9
10
  BAD_REDIS = "totally bad bogus redis handle"
10
11
 
@@ -95,13 +96,13 @@ describe 'Connection tests' do
95
96
  end
96
97
 
97
98
  it "should support local handles with a vanilla redis connection" do
98
- Redis.current = nil # reset from other tests
99
+ # Redis.current = nil # reset from other tests
99
100
  Redis::Objects.redis = nil
100
101
  @redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
101
102
 
102
103
  # Redis.current is lazily auto-populated to touch 6379
103
104
  # This why we choose the weird 9212 port to avoid
104
- Redis.current.inspect.should == Redis.new.inspect
105
+ # Redis.current.inspect.should == Redis.new.inspect
105
106
  Redis::Objects.redis.inspect.should == Redis.new.inspect
106
107
 
107
108
  v = Redis::Value.new('conn/value', @redis_handle)
@@ -140,13 +141,13 @@ describe 'Connection tests' do
140
141
  end
141
142
 
142
143
  it "should support local handles with a connection_pool" do
143
- Redis.current = nil # reset from other tests
144
+ # Redis.current = nil # reset from other tests
144
145
  Redis::Objects.redis = nil
145
146
  @redis_handle = ConnectionPool.new { Redis.new(:host => REDIS_HOST, :port => REDIS_PORT) }
146
147
 
147
148
  # Redis.current is lazily auto-populated to touch 6379
148
149
  # This why we choose the weird 9212 port to avoid
149
- Redis.current.inspect.should == Redis.new.inspect
150
+ # Redis.current.inspect.should == Redis.new.inspect
150
151
  Redis::Objects.redis.inspect.should == Redis.new.inspect
151
152
 
152
153
  v = Redis::Value.new('conn/value', @redis_handle)
@@ -184,24 +185,19 @@ describe 'Connection tests' do
184
185
  c.decr(1)
185
186
  end
186
187
 
187
- it "should support Redis.current" do
188
- Redis.current = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
189
-
190
- Redis::Value.new('conn/value').should == 'yay'
191
- Redis::HashKey.new('conn/hash').keys.should == ['k']
192
- Redis::List.new('conn/list').sort.should == ['3', '4', '5']
193
- Redis::Set.new('conn/set').sort.should == ['5', '6', '7']
194
- Redis::SortedSet.new('conn/zset').should == ['d', 'b', 'a', 'c']
195
- Redis::Counter.new('conn/counter').should == 2
188
+ it "should properly support fallback handle variables" do
189
+ # Redis.current is lazily auto-populated to touch 6379
190
+ # This why we choose the weird 9212 port to avoid
191
+ old_redis = $redis
192
+ $redis = BAD_REDIS
193
+ Redis::Objects.redis.should == BAD_REDIS
194
+ $redis = old_redis
196
195
  end
197
196
 
198
197
  it "should support Redis::Objects.redis= with a connection_pool" do
198
+ # reset redis
199
199
  @redis_handle = ConnectionPool.new { Redis.new(:host => REDIS_HOST, :port => REDIS_PORT) }
200
-
201
- # Redis.current is lazily auto-populated to touch 6379
202
- # This why we choose the weird 9212 port to avoid
203
- Redis.current = BAD_REDIS
204
- Redis::Objects.redis.should == BAD_REDIS
200
+ Redis::Objects.redis = @redis_handle
205
201
 
206
202
  # This set of tests sucks, it fucks up the per-data-type handles
207
203
  # because Redis.current is then set to a BS value, and the lazy
@@ -229,13 +225,8 @@ describe 'Connection tests' do
229
225
 
230
226
  it "should support Redis::Objects.redis= with a vanilla redis connection" do
231
227
  # reset redis
232
- Redis::Objects.redis = nil
233
228
  @redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
234
-
235
- # Redis.current is lazily auto-populated to touch 6379
236
- # This why we choose the weird 9212 port to avoid
237
- Redis.current = BAD_REDIS
238
- Redis::Objects.redis.should == BAD_REDIS
229
+ Redis::Objects.redis = @redis_handle
239
230
 
240
231
  # This set of tests sucks, it fucks up the per-data-type handles
241
232
  # because Redis.current is then set to a BS value, and the lazy
@@ -260,7 +251,7 @@ describe 'Connection tests' do
260
251
  Redis::Counter.new('conn/counter').should == 2
261
252
 
262
253
  # Fix for future tests
263
- Redis.current = @redis_handle
254
+ # Redis.current = @redis_handle
264
255
  end
265
256
 
266
257
  it "should support pipelined changes" do
@@ -0,0 +1,199 @@
1
+
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ require 'redis/objects'
5
+ Redis::Objects.redis = REDIS_HANDLE
6
+
7
+ class CustomSerializer
8
+ class << self
9
+ attr_accessor :dump_called, :load_called, :dump_args, :load_args
10
+ end
11
+
12
+ def self.dump(value, *args, **kargs)
13
+ @dump_called = true
14
+ @dump_args = [args, kargs]
15
+ Marshal.dump(value)
16
+ end
17
+
18
+ def self.load(value, *args, **kargs)
19
+ @load_called = true
20
+ @load_args = [args, kargs]
21
+ Marshal.load(value)
22
+ end
23
+
24
+ def self.reset!
25
+ @dump_called = nil
26
+ @load_called = nil
27
+ end
28
+ end
29
+
30
+ describe 'with custom serialization' do
31
+ before do
32
+ CustomSerializer.reset!
33
+ end
34
+
35
+ describe Redis::Value do
36
+ before do
37
+ @value = Redis::Value.new(
38
+ 'spec/value_custom_serializer',
39
+ marshal: true,
40
+ serializer: CustomSerializer
41
+ )
42
+ @value.clear
43
+ end
44
+
45
+ it 'uses custom serializer' do
46
+ @value.value = { json: 'data' }
47
+ CustomSerializer.dump_called.should == true
48
+ CustomSerializer.load_called.should == nil
49
+ @value.value.should == { json: 'data' }
50
+ CustomSerializer.dump_called.should == true
51
+ CustomSerializer.load_called.should == true
52
+ end
53
+
54
+ it 'passes extra arguments to dump' do
55
+ @value.options[:marshal_dump_args] = ['some', { extra: 'arguments' }]
56
+ @value.value = 1
57
+ CustomSerializer.dump_args.should == [['some'], { extra: 'arguments' }]
58
+ end
59
+
60
+ it 'passes extra arguments to load' do
61
+ @value.options[:marshal_load_args] = ['some', { extra: 'arguments' }]
62
+ @value.value = 1
63
+ @value.value.should == 1
64
+ CustomSerializer.load_args.should == [['some'], { extra: 'arguments' }]
65
+ end
66
+ end
67
+
68
+ describe Redis::List do
69
+ before do
70
+ @list = Redis::List.new(
71
+ 'spec/list_custom_serializer',
72
+ marshal: true,
73
+ serializer: CustomSerializer
74
+ )
75
+ @list.clear
76
+ end
77
+
78
+ it 'uses custom serializer' do
79
+ @list << { json: 'data' }
80
+ CustomSerializer.dump_called.should == true
81
+ CustomSerializer.load_called.should == nil
82
+ @list.should == [{ json: 'data' }]
83
+ CustomSerializer.dump_called.should == true
84
+ CustomSerializer.load_called.should == true
85
+ end
86
+
87
+ it 'passes extra arguments to dump' do
88
+ @list.options[:marshal_dump_args] = ['some', { extra: 'arguments' }]
89
+ @list << 1
90
+ CustomSerializer.dump_args.should == [['some'], { extra: 'arguments' }]
91
+ end
92
+
93
+ it 'passes extra arguments to load' do
94
+ @list.options[:marshal_load_args] = ['some', { extra: 'arguments' }]
95
+ @list << 1
96
+ @list.values.should == [1]
97
+ CustomSerializer.load_args.should == [['some'], { extra: 'arguments' }]
98
+ end
99
+ end
100
+
101
+ describe Redis::HashKey do
102
+ before do
103
+ @hash = Redis::HashKey.new(
104
+ 'spec/hash_custom_serializer',
105
+ marshal: true,
106
+ serializer: CustomSerializer
107
+ )
108
+ @hash.clear
109
+ end
110
+
111
+ it 'uses custom serializer' do
112
+ @hash['a'] = 1
113
+ CustomSerializer.dump_called.should == true
114
+ CustomSerializer.load_called.should == nil
115
+ @hash.value.should == { 'a' => 1 }
116
+ CustomSerializer.dump_called.should == true
117
+ CustomSerializer.load_called.should == true
118
+ end
119
+
120
+ it 'passes extra arguments to dump' do
121
+ @hash.options[:marshal_dump_args] = ['some', { extra: 'arguments' }]
122
+ @hash['a'] = 1
123
+ CustomSerializer.dump_args.should == [['some'], { extra: 'arguments' }]
124
+ end
125
+
126
+ it 'passes extra arguments to load' do
127
+ @hash.options[:marshal_load_args] = ['some', { extra: 'arguments' }]
128
+ @hash['a'] = 1
129
+ @hash.value.should == { 'a' => 1 }
130
+ CustomSerializer.load_args.should == [['some'], { extra: 'arguments' }]
131
+ end
132
+ end
133
+
134
+ describe Redis::Set do
135
+ before do
136
+ @set = Redis::Set.new(
137
+ 'spec/set_custom_serializer',
138
+ marshal: true,
139
+ serializer: CustomSerializer
140
+ )
141
+ @set.clear
142
+ end
143
+
144
+ it 'uses custom serializer' do
145
+ @set << 'a'
146
+ CustomSerializer.dump_called.should == true
147
+ CustomSerializer.load_called.should == nil
148
+ @set.members.should == ['a']
149
+ CustomSerializer.dump_called.should == true
150
+ CustomSerializer.load_called.should == true
151
+ end
152
+
153
+ it 'passes extra arguments to dump' do
154
+ @set.options[:marshal_dump_args] = ['some', { extra: 'arguments' }]
155
+ @set << 'a'
156
+ CustomSerializer.dump_args.should == [['some'], { extra: 'arguments' }]
157
+ end
158
+
159
+ it 'passes extra arguments to load' do
160
+ @set.options[:marshal_load_args] = ['some', { extra: 'arguments' }]
161
+ @set << 'a'
162
+ @set.members.should == ['a']
163
+ CustomSerializer.load_args.should == [['some'], { extra: 'arguments' }]
164
+ end
165
+ end
166
+
167
+ describe Redis::SortedSet do
168
+ before do
169
+ @set = Redis::SortedSet.new(
170
+ 'spec/zset_custom_serializer',
171
+ marshal: true,
172
+ serializer: CustomSerializer
173
+ )
174
+ @set.clear
175
+ end
176
+
177
+ it 'uses custom serializer' do
178
+ @set['a'] = 1
179
+ CustomSerializer.dump_called.should == true
180
+ CustomSerializer.load_called.should == nil
181
+ @set.members.should == ['a']
182
+ CustomSerializer.dump_called.should == true
183
+ CustomSerializer.load_called.should == true
184
+ end
185
+
186
+ it 'passes extra arguments to dump' do
187
+ @set.options[:marshal_dump_args] = ['some', { extra: 'arguments' }]
188
+ @set['a'] = 1
189
+ CustomSerializer.dump_args.should == [['some'], { extra: 'arguments' }]
190
+ end
191
+
192
+ it 'passes extra arguments to load' do
193
+ @set.options[:marshal_load_args] = ['some', { extra: 'arguments' }]
194
+ @set['a'] = 1
195
+ @set.members.should == ['a']
196
+ CustomSerializer.load_args.should == [['some'], { extra: 'arguments' }]
197
+ end
198
+ end
199
+ end
@@ -2,6 +2,7 @@
2
2
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
3
 
4
4
  require 'redis/objects'
5
+ Redis::Objects.redis = REDIS_HANDLE
5
6
 
6
7
  describe Redis::Value do
7
8
  before do
@@ -19,6 +20,21 @@ describe Redis::Value do
19
20
  @value.value.should == false
20
21
  end
21
22
 
23
+ it "should handle simple values" do
24
+ @value.should == nil
25
+ @value.value = 'Trevor Hoffman'
26
+ @value.should == 'Trevor Hoffman'
27
+ @value.get.should == 'Trevor Hoffman'
28
+ @value.exists?.should == true
29
+ @value.exists.should == 1
30
+ @value.del.should == 1
31
+ @value.should.be.nil
32
+ @value.exists?.should == false
33
+ @value.exists.should == 0
34
+ @value.value = 42
35
+ @value.value.should == '42'
36
+ end
37
+
22
38
  it "should compress non marshaled values" do
23
39
  @value = Redis::Value.new('spec/value', compress: true)
24
40
  @value.value = 'Trevor Hoffman'
@@ -39,17 +55,8 @@ describe Redis::Value do
39
55
  @value.value.should == nil
40
56
  @value.value = ''
41
57
  @value.value.should == ''
42
- end
43
-
44
- it "should handle simple values" do
45
- @value.should == nil
46
- @value.value = 'Trevor Hoffman'
47
- @value.should == 'Trevor Hoffman'
48
- @value.get.should == 'Trevor Hoffman'
49
- @value.del.should == 1
50
- @value.should.be.nil
51
- @value.value = 42
52
- @value.value.should == '42'
58
+ @value.delete
59
+ @value.value.should.be.nil
53
60
  end
54
61
 
55
62
  it "should handle complex marshaled values" do
@@ -88,7 +95,7 @@ describe Redis::Value do
88
95
  marshalled_string = Marshal.dump({json: 'marshal'})
89
96
  @value = Redis::Value.new('spec/marshal', :default => marshalled_string, :marshal => true)
90
97
  @value.value.should == marshalled_string
91
- @value.clear
98
+ @value.delete
92
99
  end
93
100
 
94
101
  it "should support renaming values" do
@@ -499,23 +506,56 @@ describe Redis::Counter do
499
506
  @counter.incrbyfloat 2.0e2
500
507
  @counter.to_f.should == 5214.31
501
508
  @counter.clear
509
+ @counter.should.be.nil
502
510
  end
503
511
 
504
512
  it "should support an atomic block" do
505
513
  @counter = Redis::Counter.new("spec/block_counter")
506
514
  @counter.should == 0
507
515
  @counter.increment(1)
508
- # The block is never executed.
509
- @updated =
510
- @counter.increment(1) do |updated|
511
- if updated == 2
512
- 'yep'
513
- else
514
- raise("test failed")
515
- end
516
- end
516
+
517
+ # successfully increments
518
+ @updated = @counter.increment(1) { |updated| updated == 2 ? 'yep' : nil }
519
+ @updated.should == 'yep'
520
+ @counter.should == 2
521
+
522
+ # fails to increment
523
+ @updated = @counter.increment(1) { |updated| updated == 2 ? 'yep' : nil }
524
+ @updated.should == nil
525
+ @counter.should == 2
526
+
527
+ # successfully increments by float
528
+ @updated = @counter.incrbyfloat(1.5) { |updated| updated == 3.5 ? 'yep' : nil }
529
+ @updated.should == 'yep'
530
+ @counter.should == 3.5
531
+
532
+ # fails to increment by float
533
+ @updated = @counter.incrbyfloat(2.5) { |updated| updated == 5 ? 'yep' : nil }
534
+ @updated.should == nil
535
+ @counter.should == 3.5
536
+
537
+ # fails to decrement by float
538
+ @updated = @counter.decrbyfloat(0.5) { |updated| updated == 5 ? 'yep' : nil }
539
+ @updated.should == nil
540
+ @counter.should == 3.5
541
+
542
+ # successfully decrements by float
543
+ @updated = @counter.decrbyfloat(0.5) { |updated| updated == 3 ? 'yep' : nil }
544
+ @updated.should == 'yep'
545
+ @counter.should == 3
546
+
547
+ # fails to decrement
548
+ @updated = @counter.decrement(1) { |updated| updated == 3 ? 'yep' : nil }
549
+ @updated.should == nil
550
+ @counter.should == 3
551
+
552
+ # successfully decrements
553
+ @updated = @counter.decrement(1) { |updated| updated == 2 ? 'yep' : nil }
517
554
  @updated.should == 'yep'
518
555
  @counter.should == 2
556
+
557
+ @counter.value = nil
558
+ @counter.should == 0
519
559
  end
520
560
 
521
561
  it "should support #to_json" do
@@ -615,7 +655,7 @@ describe Redis::Lock do
615
655
  REDIS_HANDLE.get("test_lock").should.be.nil
616
656
  end
617
657
 
618
- it "should not let non-expired locks be gettable" do
658
+ it "should not let blocks execute if they timeout" do
619
659
  expiry = 15
620
660
  lock = Redis::Lock.new(:test_lock, :expiration => expiry, :timeout => 0.1)
621
661
 
@@ -640,19 +680,68 @@ describe Redis::Lock do
640
680
  REDIS_HANDLE.get("test_lock").should.not.be.nil
641
681
  end
642
682
 
683
+ it "should handle a timeout of 0" do
684
+ expiry = 15
685
+ lock = Redis::Lock.new(:test_lock, :timeout => 0)
686
+
687
+ # create a fake lock
688
+ REDIS_HANDLE.set("test_lock", (Time.now + expiry).to_f)
689
+
690
+ gotit = false
691
+ error = nil
692
+ begin
693
+ lock.lock do
694
+ gotit = true
695
+ end
696
+ rescue => error
697
+ end
698
+
699
+ error.should.be.kind_of(Redis::Lock::LockTimeout)
700
+
701
+ # should not have the lock
702
+ gotit.should.not.be.true
703
+
704
+ # lock value should still be set
705
+ REDIS_HANDLE.get("test_lock").should.not.be.nil
706
+ end
707
+
708
+ it "should properly keep the lock across threads" do
709
+ lock = Redis::Lock.new(:test_lock0)
710
+
711
+ t1 = Thread.new do
712
+ lock.lock do
713
+ lock.exists?.should.be.true if RUNNING_LOCALLY
714
+ REDIS_HANDLE.exists?("test_lock0").should.be.true if RUNNING_LOCALLY
715
+ sleep 1.0 # hang onto the lock across other thread
716
+ end
717
+ end
718
+
719
+ t2 = Thread.new do
720
+ # check for the lock from another thread
721
+ lock.exists?.should.be.true if RUNNING_LOCALLY
722
+ REDIS_HANDLE.exists?("test_lock0").should.be.true if RUNNING_LOCALLY
723
+ end
724
+
725
+ t1.join
726
+ t2.join
727
+
728
+ # lock value should not be set since the lock was held for more than the expiry
729
+ lock.exists?.should.be.false
730
+ REDIS_HANDLE.exists?("test_lock0").should.be.false
731
+ end
732
+
643
733
  it "Redis should remove the key if lock is held past expiration" do
644
- lock = Redis::Lock.new(:test_lock, :expiration => 0.1)
734
+ lock = Redis::Lock.new(:test_lock1, :expiration => 0.1)
645
735
 
646
736
  lock.lock do
647
- REDIS_HANDLE.exists("test_lock").should.be.true
648
- sleep 0.3
649
- # technically undefined behavior because we don't have a BG thread
650
- # running and deleting lock keys - that is only triggered on block exit
651
- #REDIS_HANDLE.exists("test_lock").should.be.false
737
+ lock.exists?.should.be.true
738
+ REDIS_HANDLE.exists?("test_lock1").should.be.true
739
+ sleep 1.0 # hang onto the lock > expiry
652
740
  end
653
741
 
654
742
  # lock value should not be set since the lock was held for more than the expiry
655
- REDIS_HANDLE.exists("test_lock").should.be.false
743
+ lock.exists?.should.be.false
744
+ REDIS_HANDLE.exists?("test_lock1").should.be.false
656
745
  end
657
746
 
658
747
 
@@ -660,9 +749,9 @@ describe Redis::Lock do
660
749
  lock = Redis::Lock.new(:test_lock2, :expiration => 0.1)
661
750
 
662
751
  lock.lock do
663
- REDIS_HANDLE.exists("test_lock2").should.be.true
664
- sleep 0.3 # expired, key is deleted
665
- REDIS_HANDLE.exists("test_lock2").should.be.false
752
+ REDIS_HANDLE.exists?("test_lock2").should.be.true
753
+ sleep 1.0 # expired, key is deleted
754
+ REDIS_HANDLE.exists?("test_lock2").should.be.false
666
755
  REDIS_HANDLE.set("test_lock2", "foo") # this is no longer a lock key, name is a coincidence
667
756
  end
668
757
 
@@ -670,17 +759,17 @@ describe Redis::Lock do
670
759
  end
671
760
 
672
761
  it "should manually delete the key if finished before expiration" do
673
- lock = Redis::Lock.new(:test_lock3, :expiration => 0.5)
762
+ lock = Redis::Lock.new(:test_lock3, :expiration => 10.0)
674
763
 
675
764
  lock.lock do
676
- REDIS_HANDLE.exists("test_lock3").should.be.true
765
+ REDIS_HANDLE.exists?("test_lock3").should.be.true
677
766
  sleep 0.1
678
- REDIS_HANDLE.exists("test_lock3").should.be.true
767
+ REDIS_HANDLE.exists?("test_lock3").should.be.true
679
768
  end
680
769
 
681
- # should delete the key because the lock block is done, regardless of time
770
+ # should delete the key because the lock block is done, regardless of expiry
682
771
  # for some strange reason, I have seen this test fail randomly, which is worrisome.
683
- #REDIS_HANDLE.exists("test_lock3").should.be.false
772
+ REDIS_HANDLE.exists?("test_lock3").should.be.false
684
773
  end
685
774
 
686
775
 
@@ -900,6 +989,13 @@ describe Redis::HashKey do
900
989
  hsh['foo'].should == 'bar'
901
990
  end
902
991
 
992
+ it "should return multiple items via bulk_values" do
993
+ @hash['taco'] = 42
994
+ @hash['burrito'] = 99
995
+ res = @hash.bulk_values('taco', 'burrito')
996
+ res.should == ['42', '99'] # hashes don't convert
997
+ end
998
+
903
999
  it "should increment field" do
904
1000
  @hash.incr('counter')
905
1001
  @hash.incr('counter')
@@ -1007,7 +1103,9 @@ describe Redis::Set do
1007
1103
 
1008
1104
  it "should handle sets of simple values" do
1009
1105
  @set.should.be.empty
1010
- @set << 'a' << 'a' << 'a'
1106
+ @set << 'a'
1107
+ @set.randmember.should == 'a'
1108
+ @set << 'a' << 'a'
1011
1109
  @set.should == ['a']
1012
1110
  @set.to_s.should == 'a'
1013
1111
  @set.get.should == ['a']
@@ -1048,11 +1146,13 @@ describe Redis::Set do
1048
1146
  coll = @set.select{|st| st == 'c'}
1049
1147
  coll.should == ['c']
1050
1148
  @set.sort.should == ['a','b','c']
1149
+ @set.randmember.should.not == 'd'
1051
1150
  @set.delete_if{|m| m == 'c'}
1052
1151
  @set.sort.should == ['a','b']
1053
1152
 
1054
1153
  @set << nil
1055
1154
  @set.include?("").should.be.true
1155
+ @set.sort.should == ['','a','b']
1056
1156
  end
1057
1157
 
1058
1158
  it "should handle empty array adds" do
@@ -1168,6 +1268,12 @@ describe Redis::Set do
1168
1268
  @set_1.value.should == ['a']
1169
1269
  end
1170
1270
 
1271
+ it "should support moving between sets" do
1272
+ @set_1 << 'X' << 'Y' << 'Z'
1273
+ @set_1.move('X', @set_2)
1274
+ @set_2.should == ['X']
1275
+ end
1276
+
1171
1277
  it "should respond to #to_json" do
1172
1278
  @set_1 << 'a'
1173
1279
  JSON.parse(@set_1.to_json)['value'].should == ['a']
@@ -1267,6 +1373,9 @@ describe Redis::SortedSet do
1267
1373
  @set.to_s.should == 'a, b'
1268
1374
  @set.should == ['a','b']
1269
1375
  @set.members.should == ['a','b']
1376
+ @set.member?('a').should == true
1377
+ @set.member?('b').should == true
1378
+ @set.member?('c').should == false
1270
1379
  @set['d'] = 0
1271
1380
 
1272
1381
  @set.rangebyscore(0, 4).should == ['d','a']
@@ -1316,6 +1425,10 @@ describe Redis::SortedSet do
1316
1425
 
1317
1426
  @set.delete_if{|m| m == 'b'}
1318
1427
  @set.size.should == 3
1428
+
1429
+ # this is destructive so must come last
1430
+ res = @set.remrangebyrank(0, 2)
1431
+ res.should == 3
1319
1432
  end
1320
1433
 
1321
1434
  it "should handle inserting multiple values at once" do