mock_redis 0.5.4 → 0.31.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (201) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/lint.yml +31 -0
  3. data/.github/workflows/tests.yml +63 -0
  4. data/.gitignore +1 -1
  5. data/.overcommit.yml +21 -0
  6. data/.rspec +1 -1
  7. data/.rubocop.yml +148 -0
  8. data/.rubocop_todo.yml +35 -0
  9. data/.simplecov +4 -0
  10. data/CHANGELOG.md +278 -0
  11. data/Gemfile +9 -5
  12. data/LICENSE.md +21 -0
  13. data/README.md +52 -16
  14. data/Rakefile +0 -8
  15. data/lib/mock_redis/assertions.rb +0 -1
  16. data/lib/mock_redis/connection_method.rb +13 -0
  17. data/lib/mock_redis/database.rb +193 -257
  18. data/lib/mock_redis/expire_wrapper.rb +2 -2
  19. data/lib/mock_redis/future.rb +23 -0
  20. data/lib/mock_redis/geospatial_methods.rb +240 -0
  21. data/lib/mock_redis/hash_methods.rb +83 -24
  22. data/lib/mock_redis/indifferent_hash.rb +11 -0
  23. data/lib/mock_redis/info_method.rb +160 -0
  24. data/lib/mock_redis/list_methods.rb +34 -19
  25. data/lib/mock_redis/multi_db_wrapper.rb +8 -7
  26. data/lib/mock_redis/pipelined_wrapper.rb +42 -16
  27. data/lib/mock_redis/set_methods.rb +62 -19
  28. data/lib/mock_redis/sort_method.rb +81 -0
  29. data/lib/mock_redis/stream/id.rb +58 -0
  30. data/lib/mock_redis/stream.rb +88 -0
  31. data/lib/mock_redis/stream_methods.rb +102 -0
  32. data/lib/mock_redis/string_methods.rb +235 -42
  33. data/lib/mock_redis/transaction_wrapper.rb +62 -28
  34. data/lib/mock_redis/utility_methods.rb +62 -11
  35. data/lib/mock_redis/version.rb +4 -1
  36. data/lib/mock_redis/zset.rb +24 -29
  37. data/lib/mock_redis/zset_methods.rb +187 -59
  38. data/lib/mock_redis.rb +77 -27
  39. data/mock_redis.gemspec +23 -15
  40. data/spec/client_spec.rb +29 -0
  41. data/spec/cloning_spec.rb +17 -18
  42. data/spec/commands/append_spec.rb +4 -4
  43. data/spec/commands/auth_spec.rb +1 -1
  44. data/spec/commands/bgrewriteaof_spec.rb +2 -2
  45. data/spec/commands/bgsave_spec.rb +2 -2
  46. data/spec/commands/bitcount_spec.rb +25 -0
  47. data/spec/commands/bitfield_spec.rb +169 -0
  48. data/spec/commands/blpop_spec.rb +19 -21
  49. data/spec/commands/brpop_spec.rb +25 -20
  50. data/spec/commands/brpoplpush_spec.rb +16 -17
  51. data/spec/commands/connected_spec.rb +7 -0
  52. data/spec/commands/connection_spec.rb +15 -0
  53. data/spec/commands/dbsize_spec.rb +3 -3
  54. data/spec/commands/decr_spec.rb +8 -8
  55. data/spec/commands/decrby_spec.rb +8 -8
  56. data/spec/commands/del_spec.rb +35 -3
  57. data/spec/commands/disconnect_spec.rb +7 -0
  58. data/spec/commands/dump_spec.rb +19 -0
  59. data/spec/commands/echo_spec.rb +4 -4
  60. data/spec/commands/eval_spec.rb +7 -0
  61. data/spec/commands/evalsha_spec.rb +10 -0
  62. data/spec/commands/exists_spec.rb +36 -7
  63. data/spec/commands/expire_spec.rb +48 -20
  64. data/spec/commands/expireat_spec.rb +12 -13
  65. data/spec/commands/flushall_spec.rb +5 -5
  66. data/spec/commands/flushdb_spec.rb +5 -5
  67. data/spec/commands/future_spec.rb +30 -0
  68. data/spec/commands/geoadd_spec.rb +58 -0
  69. data/spec/commands/geodist_spec.rb +118 -0
  70. data/spec/commands/geohash_spec.rb +52 -0
  71. data/spec/commands/geopos_spec.rb +55 -0
  72. data/spec/commands/get_spec.rb +14 -6
  73. data/spec/commands/getbit_spec.rb +7 -7
  74. data/spec/commands/getrange_spec.rb +9 -9
  75. data/spec/commands/getset_spec.rb +7 -7
  76. data/spec/commands/hdel_spec.rb +41 -11
  77. data/spec/commands/hexists_spec.rb +11 -11
  78. data/spec/commands/hget_spec.rb +7 -7
  79. data/spec/commands/hgetall_spec.rb +15 -5
  80. data/spec/commands/hincrby_spec.rb +16 -16
  81. data/spec/commands/hincrbyfloat_spec.rb +58 -0
  82. data/spec/commands/hkeys_spec.rb +5 -5
  83. data/spec/commands/hlen_spec.rb +5 -5
  84. data/spec/commands/hmget_spec.rb +19 -9
  85. data/spec/commands/hmset_spec.rb +38 -12
  86. data/spec/commands/hscan_each_spec.rb +48 -0
  87. data/spec/commands/hscan_spec.rb +27 -0
  88. data/spec/commands/hset_spec.rb +26 -12
  89. data/spec/commands/hsetnx_spec.rb +16 -16
  90. data/spec/commands/hvals_spec.rb +5 -5
  91. data/spec/commands/incr_spec.rb +8 -8
  92. data/spec/commands/incrby_spec.rb +13 -13
  93. data/spec/commands/incrbyfloat_spec.rb +13 -13
  94. data/spec/commands/info_spec.rb +54 -5
  95. data/spec/commands/keys_spec.rb +83 -31
  96. data/spec/commands/lastsave_spec.rb +2 -2
  97. data/spec/commands/lindex_spec.rb +20 -10
  98. data/spec/commands/linsert_spec.rb +14 -14
  99. data/spec/commands/llen_spec.rb +4 -4
  100. data/spec/commands/lpop_spec.rb +6 -6
  101. data/spec/commands/lpush_spec.rb +21 -15
  102. data/spec/commands/lpushx_spec.rb +24 -11
  103. data/spec/commands/lrange_spec.rb +24 -8
  104. data/spec/commands/lrem_spec.rb +16 -16
  105. data/spec/commands/lset_spec.rb +17 -12
  106. data/spec/commands/ltrim_spec.rb +17 -7
  107. data/spec/commands/mapped_hmget_spec.rb +13 -9
  108. data/spec/commands/mapped_hmset_spec.rb +12 -12
  109. data/spec/commands/mapped_mget_spec.rb +22 -0
  110. data/spec/commands/mapped_mset_spec.rb +19 -0
  111. data/spec/commands/mapped_msetnx_spec.rb +26 -0
  112. data/spec/commands/mget_spec.rb +48 -17
  113. data/spec/commands/move_spec.rb +37 -37
  114. data/spec/commands/mset_spec.rb +20 -6
  115. data/spec/commands/msetnx_spec.rb +14 -14
  116. data/spec/commands/persist_spec.rb +15 -16
  117. data/spec/commands/pexpire_spec.rb +86 -0
  118. data/spec/commands/pexpireat_spec.rb +48 -0
  119. data/spec/commands/ping_spec.rb +6 -2
  120. data/spec/commands/pipelined_spec.rb +98 -7
  121. data/spec/commands/pttl_spec.rb +41 -0
  122. data/spec/commands/randomkey_spec.rb +3 -3
  123. data/spec/commands/rename_spec.rb +16 -12
  124. data/spec/commands/renamenx_spec.rb +13 -15
  125. data/spec/commands/restore_spec.rb +47 -0
  126. data/spec/commands/rpop_spec.rb +6 -6
  127. data/spec/commands/rpoplpush_spec.rb +13 -8
  128. data/spec/commands/rpush_spec.rb +21 -15
  129. data/spec/commands/rpushx_spec.rb +24 -11
  130. data/spec/commands/sadd_spec.rb +14 -10
  131. data/spec/commands/scan_each_spec.rb +39 -0
  132. data/spec/commands/scan_spec.rb +64 -0
  133. data/spec/commands/scard_spec.rb +3 -3
  134. data/spec/commands/script_spec.rb +9 -0
  135. data/spec/commands/sdiff_spec.rb +13 -13
  136. data/spec/commands/sdiffstore_spec.rb +13 -13
  137. data/spec/commands/select_spec.rb +13 -5
  138. data/spec/commands/set_spec.rb +112 -0
  139. data/spec/commands/setbit_spec.rb +25 -16
  140. data/spec/commands/setex_spec.rb +20 -4
  141. data/spec/commands/setnx_spec.rb +6 -6
  142. data/spec/commands/setrange_spec.rb +12 -12
  143. data/spec/commands/sinter_spec.rb +11 -13
  144. data/spec/commands/sinterstore_spec.rb +12 -12
  145. data/spec/commands/sismember_spec.rb +10 -10
  146. data/spec/commands/smembers_spec.rb +15 -5
  147. data/spec/commands/smove_spec.rb +13 -13
  148. data/spec/commands/sort_list_spec.rb +21 -0
  149. data/spec/commands/sort_set_spec.rb +21 -0
  150. data/spec/commands/sort_zset_spec.rb +21 -0
  151. data/spec/commands/spop_spec.rb +19 -4
  152. data/spec/commands/srandmember_spec.rb +28 -4
  153. data/spec/commands/srem_spec.rb +17 -12
  154. data/spec/commands/sscan_each_spec.rb +48 -0
  155. data/spec/commands/sscan_spec.rb +39 -0
  156. data/spec/commands/strlen_spec.rb +4 -5
  157. data/spec/commands/sunion_spec.rb +13 -11
  158. data/spec/commands/sunionstore_spec.rb +12 -12
  159. data/spec/commands/ttl_spec.rb +11 -6
  160. data/spec/commands/type_spec.rb +1 -1
  161. data/spec/commands/watch_spec.rb +9 -4
  162. data/spec/commands/xadd_spec.rb +122 -0
  163. data/spec/commands/xlen_spec.rb +22 -0
  164. data/spec/commands/xrange_spec.rb +164 -0
  165. data/spec/commands/xread_spec.rb +66 -0
  166. data/spec/commands/xrevrange_spec.rb +130 -0
  167. data/spec/commands/xtrim_spec.rb +36 -0
  168. data/spec/commands/zadd_spec.rb +100 -11
  169. data/spec/commands/zcard_spec.rb +4 -4
  170. data/spec/commands/zcount_spec.rb +18 -10
  171. data/spec/commands/zincrby_spec.rb +6 -6
  172. data/spec/commands/zinterstore_spec.rb +54 -20
  173. data/spec/commands/zpopmax_spec.rb +60 -0
  174. data/spec/commands/zpopmin_spec.rb +60 -0
  175. data/spec/commands/zrange_spec.rb +54 -13
  176. data/spec/commands/zrangebyscore_spec.rb +42 -27
  177. data/spec/commands/zrank_spec.rb +4 -4
  178. data/spec/commands/zrem_spec.rb +18 -12
  179. data/spec/commands/zremrangebyrank_spec.rb +5 -5
  180. data/spec/commands/zremrangebyscore_spec.rb +12 -5
  181. data/spec/commands/zrevrange_spec.rb +35 -10
  182. data/spec/commands/zrevrangebyscore_spec.rb +26 -15
  183. data/spec/commands/zrevrank_spec.rb +4 -4
  184. data/spec/commands/zscan_each_spec.rb +48 -0
  185. data/spec/commands/zscan_spec.rb +26 -0
  186. data/spec/commands/zscore_spec.rb +7 -7
  187. data/spec/commands/zunionstore_spec.rb +54 -21
  188. data/spec/mock_redis_spec.rb +61 -0
  189. data/spec/spec_helper.rb +35 -8
  190. data/spec/support/redis_multiplexer.rb +62 -37
  191. data/spec/support/shared_examples/does_not_cleanup_empty_strings.rb +14 -0
  192. data/spec/support/shared_examples/only_operates_on_hashes.rb +5 -3
  193. data/spec/support/shared_examples/only_operates_on_lists.rb +5 -3
  194. data/spec/support/shared_examples/only_operates_on_sets.rb +5 -3
  195. data/spec/support/shared_examples/only_operates_on_strings.rb +4 -4
  196. data/spec/support/shared_examples/only_operates_on_zsets.rb +18 -16
  197. data/spec/support/shared_examples/sorts_enumerables.rb +56 -0
  198. data/spec/transactions_spec.rb +79 -29
  199. metadata +162 -42
  200. data/LICENSE +0 -19
  201. data/spec/commands/hash_operator_spec.rb +0 -21
data/lib/mock_redis.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  require 'set'
2
+ require 'ruby2_keywords'
2
3
 
3
4
  require 'mock_redis/assertions'
4
5
  require 'mock_redis/database'
5
6
  require 'mock_redis/expire_wrapper'
7
+ require 'mock_redis/future'
6
8
  require 'mock_redis/multi_db_wrapper'
7
9
  require 'mock_redis/pipelined_wrapper'
8
10
  require 'mock_redis/transaction_wrapper'
@@ -14,14 +16,16 @@ class MockRedis
14
16
  attr_reader :options
15
17
 
16
18
  DEFAULTS = {
17
- :scheme => "redis",
18
- :host => "127.0.0.1",
19
- :port => 6379,
20
- :path => nil,
21
- :timeout => 5.0,
22
- :password => nil,
23
- :db => 0,
24
- }
19
+ :scheme => 'redis',
20
+ :host => '127.0.0.1',
21
+ :port => 6379,
22
+ :path => nil,
23
+ :timeout => 5.0,
24
+ :password => nil,
25
+ :logger => nil,
26
+ :db => 0,
27
+ :time_class => Time,
28
+ }.freeze
25
29
 
26
30
  def self.connect(*args)
27
31
  new(*args)
@@ -34,40 +38,62 @@ class MockRedis
34
38
  TransactionWrapper.new(
35
39
  ExpireWrapper.new(
36
40
  MultiDbWrapper.new(
37
- Database.new(*args)))))
41
+ Database.new(self, *args)
42
+ )
43
+ )
44
+ )
45
+ )
38
46
  end
39
47
 
40
48
  def id
41
- "redis://#{self.host}:#{self.port}/#{self.db}"
49
+ "redis://#{host}:#{port}/#{db}"
42
50
  end
43
- alias :location :id
51
+ alias location id
44
52
 
45
- def call(command, &block)
46
- self.send(*command)
53
+ def call(command, &_block)
54
+ send(*command)
47
55
  end
48
56
 
49
57
  def host
50
- self.options[:host]
58
+ options[:host]
51
59
  end
52
60
 
53
61
  def port
54
- self.options[:port]
62
+ options[:port]
55
63
  end
56
64
 
57
65
  def db
58
- self.options[:db]
66
+ options[:db]
67
+ end
68
+
69
+ def logger
70
+ options[:logger]
71
+ end
72
+
73
+ def time_at(timestamp)
74
+ options[:time_class].at(timestamp)
59
75
  end
60
76
 
61
77
  def client
62
78
  self
63
79
  end
64
80
 
65
- def respond_to?(method, include_private=false)
81
+ def connect
82
+ self
83
+ end
84
+
85
+ def reconnect
86
+ self
87
+ end
88
+
89
+ def respond_to?(method, include_private = false)
66
90
  super || @db.respond_to?(method, include_private)
67
91
  end
68
92
 
69
- def method_missing(method, *args, &block)
70
- @db.send(method, *args, &block)
93
+ ruby2_keywords def method_missing(method, *args, &block)
94
+ logging([[method, *args]]) do
95
+ @db.send(method, *args, &block)
96
+ end
71
97
  end
72
98
 
73
99
  def initialize_copy(source)
@@ -75,27 +101,26 @@ class MockRedis
75
101
  @db = @db.clone
76
102
  end
77
103
 
78
-
79
104
  protected
80
105
 
81
106
  def _parse_options(options)
82
- return {} if options.nil?
107
+ return DEFAULTS.dup if options.nil?
83
108
 
84
109
  defaults = DEFAULTS.dup
85
110
 
86
- url = options[:url] || ENV["REDIS_URL"]
111
+ url = options[:url] || ENV['REDIS_URL']
87
112
 
88
113
  # Override defaults from URL if given
89
114
  if url
90
- require "uri"
115
+ require 'uri'
91
116
 
92
117
  uri = URI(url)
93
118
 
94
- if uri.scheme == "unix"
95
- defaults[:path] = uri.path
119
+ if uri.scheme == 'unix'
120
+ defaults[:path] = uri.path
96
121
  else
97
122
  # Require the URL to have at least a host
98
- raise ArgumentError, "invalid url" unless uri.host
123
+ raise ArgumentError, 'invalid url' unless uri.host
99
124
 
100
125
  defaults[:scheme] = uri.scheme
101
126
  defaults[:host] = uri.host
@@ -108,7 +133,7 @@ class MockRedis
108
133
  options = defaults.merge(options)
109
134
 
110
135
  if options[:path]
111
- options[:scheme] = "unix"
136
+ options[:scheme] = 'unix'
112
137
  options.delete(:host)
113
138
  options.delete(:port)
114
139
  else
@@ -122,4 +147,29 @@ class MockRedis
122
147
  options
123
148
  end
124
149
 
150
+ def logging(commands)
151
+ return yield unless logger&.debug?
152
+
153
+ begin
154
+ commands.each do |name, *args|
155
+ logged_args = args.map do |a|
156
+ if a.respond_to?(:inspect) then a.inspect
157
+ elsif a.respond_to?(:to_s) then a.to_s
158
+ else
159
+ # handle poorly-behaved descendants of BasicObject
160
+ klass = a.instance_exec { (class << self; self end).superclass }
161
+ "\#<#{klass}:#{a.__id__}>"
162
+ end
163
+ end
164
+ logger.debug("[MockRedis] command=#{name.to_s.upcase} args=#{logged_args.join(' ')}")
165
+ end
166
+
167
+ t1 = Time.now
168
+ yield
169
+ ensure
170
+ if t1
171
+ logger.debug(format('[MockRedis] call_time=%<time>0.2f ms', time: ((Time.now - t1) * 1000)))
172
+ end
173
+ end
174
+ end
125
175
  end
data/mock_redis.gemspec CHANGED
@@ -1,24 +1,32 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "mock_redis/version"
1
+ $LOAD_PATH << File.expand_path('lib', __dir__)
2
+ require 'mock_redis/version'
4
3
 
5
4
  Gem::Specification.new do |s|
6
- s.name = "mock_redis"
5
+ s.name = 'mock_redis'
7
6
  s.version = MockRedis::VERSION
7
+ s.license = 'MIT'
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ['Causes Engineering', 'Samuel Merritt']
10
- s.email = ['eng@causes.com']
11
- s.homepage = "https://github.com/causes/mock_redis"
12
- s.summary = %q{Redis mock that just lives in memory; useful for testing.}
9
+ s.authors = ['Shane da Silva', 'Samuel Merritt']
10
+ s.email = ['shane@dasilva.io']
11
+ s.homepage = 'https://github.com/sds/mock_redis'
12
+ s.summary = 'Redis mock that just lives in memory; useful for testing.'
13
13
 
14
- s.description = %q{Instantiate one with `redis = MockRedis.new` and treat it like you would a normal Redis object. It supports all the usual Redis operations.}
14
+ s.description = <<-MSG.strip.gsub(/\s+/, ' ')
15
+ Instantiate one with `redis = MockRedis.new` and treat it like you would a
16
+ normal Redis object. It supports all the usual Redis operations.
17
+ MSG
15
18
 
16
19
  s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
- s.require_paths = ["lib"]
20
+ s.test_files = `git ls-files -- spec/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
22
+ s.require_paths = ['lib']
20
23
 
21
- s.add_development_dependency "rake", "~> 0.9.2"
22
- s.add_development_dependency "redis", "~> 3.0.0"
23
- s.add_development_dependency "rspec", "~> 2.6.0"
24
+ s.required_ruby_version = '>= 2.4'
25
+
26
+ s.add_runtime_dependency 'ruby2_keywords'
27
+
28
+ s.add_development_dependency 'redis', '~> 4.2.0'
29
+ s.add_development_dependency 'rspec', '~> 3.0'
30
+ s.add_development_dependency 'rspec-its', '~> 1.0'
31
+ s.add_development_dependency 'timecop', '~> 0.9.1'
24
32
  end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'client' do
4
+ context '#reconnect' do
5
+ it 'reconnects' do
6
+ redis = MockRedis.new
7
+ redis.reconnect.should == redis
8
+ end
9
+ end
10
+
11
+ context '#connect' do
12
+ it 'connects' do
13
+ redis = MockRedis.new
14
+ redis.connect.should == redis
15
+ end
16
+ end
17
+
18
+ context '#disconnect!' do
19
+ it 'responds to disconnect!' do
20
+ expect(MockRedis.new).to respond_to(:disconnect!)
21
+ end
22
+ end
23
+
24
+ context '#close' do
25
+ it 'responds to close' do
26
+ expect(MockRedis.new).to respond_to(:close)
27
+ end
28
+ end
29
+ end
data/spec/cloning_spec.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "MockRedis#clone" do
3
+ describe 'MockRedis#clone' do
4
4
  before do
5
5
  @mock = MockRedis.new
6
6
  end
7
7
 
8
- context "the stored data" do
8
+ context 'the stored data' do
9
9
  before do
10
10
  @mock.set('foo', 'bar')
11
11
  @mock.hset('foohash', 'bar', 'baz')
@@ -16,60 +16,60 @@ describe "MockRedis#clone" do
16
16
  @clone = @mock.clone
17
17
  end
18
18
 
19
- it "copies the stored data to the clone" do
19
+ it 'copies the stored data to the clone' do
20
20
  @clone.get('foo').should == 'bar'
21
21
  end
22
22
 
23
- it "performs a deep copy (string values)" do
23
+ it 'performs a deep copy (string values)' do
24
24
  @mock.del('foo')
25
25
  @clone.get('foo').should == 'bar'
26
26
  end
27
27
 
28
- it "performs a deep copy (list values)" do
28
+ it 'performs a deep copy (list values)' do
29
29
  @mock.lpop('foolist')
30
30
  @clone.lrange('foolist', 0, 1).should == ['bar']
31
31
  end
32
32
 
33
- it "performs a deep copy (hash values)" do
33
+ it 'performs a deep copy (hash values)' do
34
34
  @mock.hset('foohash', 'bar', 'quux')
35
- @clone.hgetall('foohash').should == {'bar' => 'baz'}
35
+ @clone.hgetall('foohash').should == { 'bar' => 'baz' }
36
36
  end
37
37
 
38
- it "performs a deep copy (set values)" do
38
+ it 'performs a deep copy (set values)' do
39
39
  @mock.srem('fooset', 'bar')
40
40
  @clone.smembers('fooset').should == ['bar']
41
41
  end
42
42
 
43
- it "performs a deep copy (zset values)" do
43
+ it 'performs a deep copy (zset values)' do
44
44
  @mock.zadd('foozset', 2, 'bar')
45
45
  @clone.zscore('foozset', 'bar').should == 1.0
46
46
  end
47
47
  end
48
48
 
49
- context "expiration times" do
49
+ context 'expiration times' do
50
50
  before do
51
51
  @mock.set('foo', 1)
52
- @mock.expire('foo', 60026)
52
+ @mock.expire('foo', 60_026)
53
53
 
54
54
  @clone = @mock.clone
55
55
  end
56
56
 
57
- it "copies the expiration times" do
57
+ it 'copies the expiration times' do
58
58
  @clone.ttl('foo').should > 0
59
59
  end
60
60
 
61
- it "deep-copies the expiration times" do
61
+ it 'deep-copies the expiration times' do
62
62
  @mock.persist('foo')
63
63
  @clone.ttl('foo').should > 0
64
64
  end
65
65
 
66
- it "deep-copies the expiration times" do
66
+ it 'deep-copies the expiration times' do
67
67
  @clone.persist('foo')
68
68
  @mock.ttl('foo').should > 0
69
69
  end
70
70
  end
71
71
 
72
- context "transactional info" do
72
+ context 'transactional info' do
73
73
  before do
74
74
  @mock.multi
75
75
  @mock.incr('foo')
@@ -79,18 +79,17 @@ describe "MockRedis#clone" do
79
79
  @clone = @mock.clone
80
80
  end
81
81
 
82
- it "makes sure the clone is in a transaction" do
82
+ it 'makes sure the clone is in a transaction' do
83
83
  lambda do
84
84
  @clone.exec
85
85
  end.should_not raise_error
86
86
  end
87
87
 
88
- it "deep-copies the queued commands" do
88
+ it 'deep-copies the queued commands' do
89
89
  @clone.incrby('foo', 8)
90
90
  @clone.exec.should == [1, 3, 7, 15]
91
91
 
92
92
  @mock.exec.should == [1, 3, 7]
93
93
  end
94
94
  end
95
-
96
95
  end
@@ -3,22 +3,22 @@ require 'spec_helper'
3
3
  describe '#append(key, value)' do
4
4
  before { @key = 'mock-redis-test:append' }
5
5
 
6
- it "returns the new length of the string" do
6
+ it 'returns the new length of the string' do
7
7
  @redises.set(@key, 'porkchop')
8
8
  @redises.append(@key, 'sandwiches').should == 18
9
9
  end
10
10
 
11
- it "appends value to the previously-stored value" do
11
+ it 'appends value to the previously-stored value' do
12
12
  @redises.set(@key, 'porkchop')
13
13
  @redises.append(@key, 'sandwiches')
14
14
 
15
15
  @redises.get(@key).should == 'porkchopsandwiches'
16
16
  end
17
17
 
18
- it "treats a missing key as an empty string" do
18
+ it 'treats a missing key as an empty string' do
19
19
  @redises.append(@key, 'foo')
20
20
  @redises.get(@key).should == 'foo'
21
21
  end
22
22
 
23
- it_should_behave_like "a string-only command"
23
+ it_should_behave_like 'a string-only command'
24
24
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "#auth(password) [mock only]" do
3
+ describe '#auth(password) [mock only]' do
4
4
  it "just returns 'OK'" do
5
5
  @redises.mock.auth('foo').should == 'OK'
6
6
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "#bgrewriteaof [mock only]" do
4
- it "just returns a canned string" do
3
+ describe '#bgrewriteaof [mock only]' do
4
+ it 'just returns a canned string' do
5
5
  @redises.mock.bgrewriteaof.should =~ /append/
6
6
  end
7
7
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "#bgsave [mock only]" do
4
- it "just returns a canned string" do
3
+ describe '#bgsave [mock only]' do
4
+ it 'just returns a canned string' do
5
5
  @redises.mock.bgsave.should =~ /saving/
6
6
  end
7
7
  end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#bitcount(key [, start, end ])' do
4
+ before do
5
+ @key = 'mock-redis-test:bitcount'
6
+ @redises.set(@key, 'foobar')
7
+ end
8
+
9
+ it 'gets the number of set bits from the key' do
10
+ @redises.bitcount(@key).should == 26
11
+ end
12
+
13
+ it 'gets the number of set bits from the key in an interval' do
14
+ @redises.bitcount(@key, 0, 1000).should == 26
15
+ @redises.bitcount(@key, 0, 0).should == 4
16
+ @redises.bitcount(@key, 1, 1).should == 6
17
+ @redises.bitcount(@key, 1, -2).should == 18
18
+ end
19
+
20
+ it 'treats nonexistent keys as empty strings' do
21
+ @redises.bitcount('mock-redis-test:not-found').should == 0
22
+ end
23
+
24
+ it_should_behave_like 'a string-only command'
25
+ end
@@ -0,0 +1,169 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#bitfield(*args)' do
4
+ before :each do
5
+ @key = 'mock-redis-test:bitfield'
6
+ @redises.set(@key, '')
7
+
8
+ @redises.bitfield(@key, :set, 'i8', 0, 78)
9
+ @redises.bitfield(@key, :set, 'i8', 8, 104)
10
+ @redises.bitfield(@key, :set, 'i8', 16, -59)
11
+ @redises.bitfield(@key, :set, 'u8', 24, 78)
12
+ @redises.bitfield(@key, :set, 'u8', 32, 84)
13
+ end
14
+
15
+ context 'with a :get command' do
16
+ it 'gets a signed 8 bit value' do
17
+ @redises.bitfield(@key, :get, 'i8', 0).should == [78]
18
+ @redises.bitfield(@key, :get, 'i8', 8).should == [104]
19
+ @redises.bitfield(@key, :get, 'i8', 16).should == [-59]
20
+ end
21
+
22
+ it 'gets multiple values with multiple command args' do
23
+ @redises.bitfield(@key, :get, 'i8', 0,
24
+ :get, 'i8', 8,
25
+ :get, 'i8', 16).should == [78, 104, -59]
26
+ end
27
+
28
+ it 'gets multiple values using positional offsets' do
29
+ @redises.bitfield(@key, :get, 'i8', '#0',
30
+ :get, 'i8', '#1',
31
+ :get, 'i8', '#2').should == [78, 104, -59]
32
+ end
33
+
34
+ it 'shows an error with an invalid type' do
35
+ expect do
36
+ @redises.bitfield(@key, :get, 'u64', 0)
37
+ end.to raise_error(Redis::CommandError)
38
+ expect do
39
+ @redises.bitfield(@key, :get, 'i128', 0)
40
+ end.to raise_error(Redis::CommandError)
41
+ end
42
+
43
+ it 'does not throw an error with i64 type' do
44
+ expect do
45
+ @redises.bitfield(@key, :get, 'i64', 0)
46
+ end.to_not raise_error
47
+ end
48
+ end
49
+
50
+ context 'with a :set command' do
51
+ it 'sets the bit values for an 8 bit signed integer' do
52
+ @redises.bitfield(@key, :set, 'i8', 0, 63).should == [78]
53
+ @redises.bitfield(@key, :set, 'i8', 8, -1).should == [104]
54
+ @redises.bitfield(@key, :set, 'i8', 16, 123).should == [-59]
55
+
56
+ @redises.bitfield(@key, :get, 'i8', 0,
57
+ :get, 'i8', 8,
58
+ :get, 'i8', 16).should == [63, -1, 123]
59
+ end
60
+
61
+ it 'sets multiple values with multiple command args' do
62
+ @redises.bitfield(@key, :set, 'i8', 0, 63,
63
+ :set, 'i8', 8, -1,
64
+ :set, 'i8', 16, 123).should == [78, 104, -59]
65
+
66
+ @redises.bitfield(@key, :get, 'i8', 0,
67
+ :get, 'i8', 8,
68
+ :get, 'i8', 16).should == [63, -1, 123]
69
+ end
70
+ end
71
+
72
+ context 'with an :incrby command' do
73
+ it 'returns the incremented by value for an 8 bit signed integer' do
74
+ @redises.bitfield(@key, :incrby, 'i8', 0, 1).should == [79]
75
+ @redises.bitfield(@key, :incrby, 'i8', 8, -1).should == [103]
76
+ @redises.bitfield(@key, :incrby, 'i8', 16, 5).should == [-54]
77
+ end
78
+
79
+ context 'with an overflow of wrap (default)' do
80
+ context 'for a signed integer' do
81
+ it 'wraps the overflow to the minimum and increments from there' do
82
+ @redises.bitfield(@key, :get, 'i8', 24).should == [78]
83
+ @redises.bitfield(@key, :overflow, :wrap,
84
+ :incrby, 'i8', 0, 200).should == [22]
85
+ end
86
+
87
+ it 'wraps the underflow to the maximum value and decrements from there' do
88
+ @redises.bitfield(@key, :overflow, :wrap,
89
+ :incrby, 'i8', 16, -200).should == [-3]
90
+ end
91
+ end
92
+
93
+ context 'for an unsigned integer' do
94
+ it 'wraps the overflow back to zero and increments from there' do
95
+ @redises.bitfield(@key, :get, 'u8', 24).should == [78]
96
+ @redises.bitfield(@key, :overflow, :wrap,
97
+ :incrby, 'u8', 24, 233).should == [55]
98
+ end
99
+
100
+ it 'wraps the underflow to the maximum value and decrements from there' do
101
+ @redises.bitfield(@key, :get, 'u8', 32).should == [84]
102
+ @redises.bitfield(@key, :overflow, :wrap,
103
+ :incrby, 'u8', 32, -233).should == [107]
104
+ end
105
+ end
106
+ end
107
+
108
+ context 'with an overflow of sat' do
109
+ it 'sets the overflowed value to the maximum' do
110
+ @redises.bitfield(@key, :overflow, :sat,
111
+ :incrby, 'i8', 0, 256).should == [127]
112
+ end
113
+
114
+ it 'sets the underflowed value to the minimum' do
115
+ @redises.bitfield(@key, :overflow, :sat,
116
+ :incrby, 'i8', 16, -256).should == [-128]
117
+ end
118
+ end
119
+
120
+ context 'with an overflow of fail' do
121
+ it 'raises a redis error on an out of range value' do
122
+ @redises.bitfield(@key, :overflow, :fail,
123
+ :incrby, 'i8', 0, 256).should == [nil]
124
+
125
+ @redises.bitfield(@key, :overflow, :fail,
126
+ :incrby, 'i8', 16, -256).should == [nil]
127
+ end
128
+
129
+ it 'retains the original value after a failed increment' do
130
+ @redises.bitfield(@key, :get, 'i8', 0).should == [78]
131
+ @redises.bitfield(@key, :overflow, :fail,
132
+ :incrby, 'i8', 0, 256).should == [nil]
133
+ @redises.bitfield(@key, :get, 'i8', 0).should == [78]
134
+ end
135
+ end
136
+
137
+ context 'with multiple overflow commands in one transaction' do
138
+ it 'handles the overflow values correctly' do
139
+ @redises.bitfield(@key, :overflow, :sat,
140
+ :incrby, 'i8', 0, 256,
141
+ :incrby, 'i8', 8, -256,
142
+ :overflow, :wrap,
143
+ :incrby, 'i8', 0, 200,
144
+ :incrby, 'i8', 16, -200,
145
+ :overflow, :fail,
146
+ :incrby, 'i8', 0, 256,
147
+ :incrby, 'i8', 16, -256).should == [127, -128, 71, -3, nil, nil]
148
+ end
149
+ end
150
+
151
+ context 'with an unsupported overflow value' do
152
+ it 'raises an error' do
153
+ expect do
154
+ @redises.bitfield(@key, :overflow, :foo,
155
+ :incrby, 'i8', 0, 256)
156
+ end.to raise_error(Redis::CommandError)
157
+ end
158
+ end
159
+ end
160
+
161
+ context 'with a mixed set of commands' do
162
+ it 'returns the correct outputs' do
163
+ @redises.bitfield(@key, :set, 'i8', 0, 38,
164
+ :set, 'i8', 8, -99,
165
+ :incrby, 'i8', 16, 1,
166
+ :get, 'i8', 0).should == [78, 104, -58, 38]
167
+ end
168
+ end
169
+ end