mock_redis 0.5.4 → 0.31.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.
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