ruby-fakeredis-0.5.0/0000755000175000017500000000000012616136770014567 5ustar abhijithabhijithruby-fakeredis-0.5.0/metadata.yml0000644000175000017500000000573212616117431017072 0ustar abhijithabhijith--- !ruby/object:Gem::Specification name: fakeredis version: !ruby/object:Gem::Version version: 0.5.0 platform: ruby authors: - Guillermo Iguaran autorequire: bindir: bin cert_chain: [] date: 2014-07-01 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: redis requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '3.0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '3.0' - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '3.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '3.0' description: Fake (In-memory) driver for redis-rb. Useful for testing environment and machines without Redis. email: - guilleiguaran@gmail.com executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - ".travis.yml" - Gemfile - LICENSE - README.md - Rakefile - fakeredis.gemspec - lib/fake_redis.rb - lib/fakeredis.rb - lib/fakeredis/command_executor.rb - lib/fakeredis/expiring_hash.rb - lib/fakeredis/rspec.rb - lib/fakeredis/sort_method.rb - lib/fakeredis/sorted_set_argument_handler.rb - lib/fakeredis/sorted_set_store.rb - lib/fakeredis/transaction_commands.rb - lib/fakeredis/version.rb - lib/fakeredis/zset.rb - lib/redis/connection/memory.rb - spec/compatibility_spec.rb - spec/connection_spec.rb - spec/hashes_spec.rb - spec/keys_spec.rb - spec/lists_spec.rb - spec/memory_spec.rb - spec/server_spec.rb - spec/sets_spec.rb - spec/sort_method_spec.rb - spec/sorted_sets_spec.rb - spec/spec_helper.rb - spec/spec_helper_live_redis.rb - spec/strings_spec.rb - spec/support/shared_examples/sortable.rb - spec/transactions_spec.rb - spec/upcase_method_name_spec.rb homepage: https://guilleiguaran.github.com/fakeredis licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.2.0 signing_key: specification_version: 4 summary: Fake (In-memory) driver for redis-rb. test_files: - spec/compatibility_spec.rb - spec/connection_spec.rb - spec/hashes_spec.rb - spec/keys_spec.rb - spec/lists_spec.rb - spec/memory_spec.rb - spec/server_spec.rb - spec/sets_spec.rb - spec/sort_method_spec.rb - spec/sorted_sets_spec.rb - spec/spec_helper.rb - spec/spec_helper_live_redis.rb - spec/strings_spec.rb - spec/support/shared_examples/sortable.rb - spec/transactions_spec.rb - spec/upcase_method_name_spec.rb ruby-fakeredis-0.5.0/.gitignore0000644000175000017500000000005612616117431016551 0ustar abhijithabhijith*.gem .bundle Gemfile.lock pkg/* .rvmrc *.rbc ruby-fakeredis-0.5.0/.travis.yml0000644000175000017500000000012712616117431016671 0ustar abhijithabhijithlanguage: ruby rvm: - 1.9.2 - 1.9.3 - 2.0.0 - 2.1.1 - jruby-19mode - rbx-2 ruby-fakeredis-0.5.0/Gemfile0000644000175000017500000000030012616117431016044 0ustar abhijithabhijithsource "https://rubygems.org" gem 'rake' gem 'rdoc' platforms :rbx do gem 'racc' gem 'rubysl', '~> 2.0' gem 'psych' end # Specify your gem's dependencies in fakeredis.gemspec gemspec ruby-fakeredis-0.5.0/Rakefile0000644000175000017500000000110412616117431016221 0ustar abhijithabhijithrequire 'bundler' Bundler::GemHelper.install_tasks $:.push File.expand_path("../lib", __FILE__) require "fakeredis/version" Bundler::GemHelper.install_tasks require 'rspec/core' require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) do |spec| spec.pattern = FileList['spec/**/*_spec.rb'] spec.ruby_opts="-w" end task :default => :spec require 'rdoc/task' Rake::RDocTask.new do |rdoc| version = FakeRedis::VERSION rdoc.rdoc_dir = 'rdoc' rdoc.title = "fakeredis #{version}" rdoc.rdoc_files.include('README*') rdoc.rdoc_files.include('lib/**/*.rb') end ruby-fakeredis-0.5.0/lib/0000755000175000017500000000000012616117431015326 5ustar abhijithabhijithruby-fakeredis-0.5.0/lib/redis/0000755000175000017500000000000012616117431016434 5ustar abhijithabhijithruby-fakeredis-0.5.0/lib/redis/connection/0000755000175000017500000000000012616117431020573 5ustar abhijithabhijithruby-fakeredis-0.5.0/lib/redis/connection/memory.rb0000644000175000017500000006475112616117431022445 0ustar abhijithabhijithrequire 'set' require 'redis/connection/registry' require 'redis/connection/command_helper' require "fakeredis/command_executor" require "fakeredis/expiring_hash" require "fakeredis/sort_method" require "fakeredis/sorted_set_argument_handler" require "fakeredis/sorted_set_store" require "fakeredis/transaction_commands" require "fakeredis/zset" class Redis module Connection class Memory include Redis::Connection::CommandHelper include FakeRedis include SortMethod include TransactionCommands include CommandExecutor attr_accessor :options # Tracks all databases for all instances across the current process. # We have to be able to handle two clients with the same host/port accessing # different databases at once without overwriting each other. So we store our # "data" outside the client instances, in this class level instance method. # Client instances access it with a key made up of their host/port, and then select # which DB out of the array of them they want. Allows the access we need. def self.databases @databases ||= Hash.new {|h,k| h[k] = [] } end # Used for resetting everything in specs def self.reset_all_databases @databases = nil end def self.connect(options = {}) new(options) end def initialize(options = {}) self.options = options end def database_id @database_id ||= 0 end attr_writer :database_id def database_instance_key [options[:host], options[:port]].hash end def databases self.class.databases[database_instance_key] end def find_database id=database_id databases[id] ||= ExpiringHash.new end def data find_database end def replies @replies ||= [] end attr_writer :replies def connected? true end def connect_unix(path, timeout) end def disconnect end def timeout=(usecs) end def read replies.shift end # NOT IMPLEMENTED: # * blpop # * brpop # * brpoplpush # * subscribe # * psubscribe # * publish def flushdb databases.delete_at(database_id) "OK" end def flushall self.class.databases[database_instance_key] = [] "OK" end def auth(password) "OK" end def select(index) data_type_check(index, Integer) self.database_id = index "OK" end def info { "redis_version" => "2.6.16", "connected_clients" => "1", "connected_slaves" => "0", "used_memory" => "3187", "changes_since_last_save" => "0", "last_save_time" => "1237655729", "total_connections_received" => "1", "total_commands_processed" => "1", "uptime_in_seconds" => "36000", "uptime_in_days" => 0 } end def monitor; end def save; end def bgsave ; end def bgrewriteaof ; end def move key, destination_id raise Redis::CommandError, "ERR source and destination objects are the same" if destination_id == database_id destination = find_database(destination_id) return false unless data.has_key?(key) return false if destination.has_key?(key) destination[key] = data.delete(key) true end def get(key) data_type_check(key, String) data[key] end def getbit(key, offset) return unless data[key] data[key].unpack('B*')[0].split("")[offset].to_i end def bitcount(key, start_index = 0, end_index = -1) return 0 unless data[key] data[key][start_index..end_index].unpack('B*')[0].count("1") end def getrange(key, start, ending) return unless data[key] data[key][start..ending] end alias :substr :getrange def getset(key, value) data_type_check(key, String) data[key].tap do set(key, value) end end def mget(*keys) raise_argument_error('mget') if keys.empty? # We work with either an array, or list of arguments keys = keys.first if keys.size == 1 data.values_at(*keys) end def append(key, value) data[key] = (data[key] || "") data[key] = data[key] + value.to_s end def strlen(key) return unless data[key] data[key].size end def hgetall(key) data_type_check(key, Hash) data[key].to_a.flatten || {} end def hget(key, field) data_type_check(key, Hash) data[key] && data[key][field.to_s] end def hdel(key, field) field = field.to_s data_type_check(key, Hash) deleted = data[key] && data[key].delete(field) remove_key_for_empty_collection(key) deleted ? 1 : 0 end def hkeys(key) data_type_check(key, Hash) return [] if data[key].nil? data[key].keys end def keys(pattern = "*") data.keys.select { |key| File.fnmatch(pattern, key) } end def randomkey data.keys[rand(dbsize)] end def echo(string) string end def ping "PONG" end def lastsave Time.now.to_i end def time microseconds = (Time.now.to_f * 1000000).to_i [ microseconds / 1000000, microseconds % 1000000 ] end def dbsize data.keys.count end def exists(key) data.key?(key) end def llen(key) data_type_check(key, Array) return 0 unless data[key] data[key].size end def lrange(key, startidx, endidx) data_type_check(key, Array) (data[key] && data[key][startidx..endidx]) || [] end def ltrim(key, start, stop) data_type_check(key, Array) return unless data[key] # Example: we have a list of 3 elements and # we give it a ltrim list, -5, -1. This means # it should trim to a max of 5. Since 3 < 5 # we should not touch the list. This is consistent # with behavior of real Redis's ltrim with a negative # start argument. unless start < 0 && data[key].count < start.abs data[key] = data[key][start..stop] end "OK" end def lindex(key, index) data_type_check(key, Array) data[key] && data[key][index] end def linsert(key, where, pivot, value) data_type_check(key, Array) return unless data[key] index = data[key].index(pivot) case where when :before then data[key].insert(index, value) when :after then data[key].insert(index + 1, value) else raise_syntax_error end end def lset(key, index, value) data_type_check(key, Array) return unless data[key] raise Redis::CommandError, "ERR index out of range" if index >= data[key].size data[key][index] = value end def lrem(key, count, value) data_type_check(key, Array) return unless data[key] old_size = data[key].size diff = if count == 0 data[key].delete(value) old_size - data[key].size else array = count > 0 ? data[key].dup : data[key].reverse count.abs.times{ array.delete_at(array.index(value) || array.length) } data[key] = count > 0 ? array.dup : array.reverse old_size - data[key].size end remove_key_for_empty_collection(key) diff end def rpush(key, value) data_type_check(key, Array) data[key] ||= [] [value].flatten.each do |val| data[key].push(val.to_s) end data[key].size end def rpushx(key, value) data_type_check(key, Array) return unless data[key] rpush(key, value) end def lpush(key, value) data_type_check(key, Array) data[key] ||= [] [value].flatten.each do |val| data[key].unshift(val.to_s) end data[key].size end def lpushx(key, value) data_type_check(key, Array) return unless data[key] lpush(key, value) end def rpop(key) data_type_check(key, Array) return unless data[key] data[key].pop end def rpoplpush(key1, key2) data_type_check(key1, Array) rpop(key1).tap do |elem| lpush(key2, elem) unless elem.nil? end end def lpop(key) data_type_check(key, Array) return unless data[key] data[key].shift end def smembers(key) data_type_check(key, ::Set) return [] unless data[key] data[key].to_a.reverse end def sismember(key, value) data_type_check(key, ::Set) return false unless data[key] data[key].include?(value.to_s) end def sadd(key, value) data_type_check(key, ::Set) value = Array(value) raise_argument_error('sadd') if value.empty? result = if data[key] old_set = data[key].dup data[key].merge(value.map(&:to_s)) (data[key] - old_set).size else data[key] = ::Set.new(value.map(&:to_s)) data[key].size end # 0 = false, 1 = true, 2+ untouched return result == 1 if result < 2 result end def srem(key, value) data_type_check(key, ::Set) return false unless data[key] if value.is_a?(Array) old_size = data[key].size values = value.map(&:to_s) values.each { |value| data[key].delete(value) } deleted = old_size - data[key].size else deleted = !!data[key].delete?(value.to_s) end remove_key_for_empty_collection(key) deleted end def smove(source, destination, value) data_type_check(destination, ::Set) result = self.srem(source, value) self.sadd(destination, value) if result result end def spop(key) data_type_check(key, ::Set) elem = srandmember(key) srem(key, elem) elem end def scard(key) data_type_check(key, ::Set) return 0 unless data[key] data[key].size end def sinter(*keys) raise_argument_error('sinter') if keys.empty? keys.each { |k| data_type_check(k, ::Set) } return ::Set.new if keys.any? { |k| data[k].nil? } keys = keys.map { |k| data[k] || ::Set.new } keys.inject do |set, key| set & key end.to_a end def sinterstore(destination, *keys) data_type_check(destination, ::Set) result = sinter(*keys) data[destination] = ::Set.new(result) end def sunion(*keys) keys.each { |k| data_type_check(k, ::Set) } keys = keys.map { |k| data[k] || ::Set.new } keys.inject(::Set.new) do |set, key| set | key end.to_a end def sunionstore(destination, *keys) data_type_check(destination, ::Set) result = sunion(*keys) data[destination] = ::Set.new(result) end def sdiff(key1, *keys) [key1, *keys].each { |k| data_type_check(k, ::Set) } keys = keys.map { |k| data[k] || ::Set.new } keys.inject(data[key1] || Set.new) do |memo, set| memo - set end.to_a end def sdiffstore(destination, key1, *keys) data_type_check(destination, ::Set) result = sdiff(key1, *keys) data[destination] = ::Set.new(result) end def srandmember(key, number=nil) number.nil? ? srandmember_single(key) : srandmember_multiple(key, number) end def del(*keys) keys = keys.flatten(1) raise_argument_error('del') if keys.empty? old_count = data.keys.size keys.each do |key| data.delete(key) end old_count - data.keys.size end def setnx(key, value) if exists(key) false else set(key, value) true end end def rename(key, new_key) return unless data[key] data[new_key] = data[key] data.expires[new_key] = data.expires[key] if data.expires.include?(key) data.delete(key) end def renamenx(key, new_key) if exists(new_key) false else rename(key, new_key) true end end def expire(key, ttl) return 0 unless data[key] data.expires[key] = Time.now + ttl 1 end def ttl(key) if data.expires.include?(key) && (ttl = data.expires[key].to_i - Time.now.to_i) > 0 ttl else exists(key) ? -1 : -2 end end def expireat(key, timestamp) data.expires[key] = Time.at(timestamp) true end def persist(key) !!data.expires.delete(key) end def hset(key, field, value) data_type_check(key, Hash) field = field.to_s if data[key] result = !data[key].include?(field) data[key][field] = value.to_s result else data[key] = { field => value.to_s } true end end def hsetnx(key, field, value) data_type_check(key, Hash) field = field.to_s return false if data[key] && data[key][field] hset(key, field, value) end def hmset(key, *fields) # mapped_hmset gives us [[:k1, "v1", :k2, "v2"]] for `fields`. Fix that. fields = fields[0] if mapped_param?(fields) raise_argument_error('hmset') if fields.empty? is_list_of_arrays = fields.all?{|field| field.instance_of?(Array)} raise_argument_error('hmset') if fields.size.odd? and !is_list_of_arrays raise_argument_error('hmset') if is_list_of_arrays and !fields.all?{|field| field.length == 2} data_type_check(key, Hash) data[key] ||= {} if is_list_of_arrays fields.each do |pair| data[key][pair[0].to_s] = pair[1].to_s end else fields.each_slice(2) do |field| data[key][field[0].to_s] = field[1].to_s end end end def hmget(key, *fields) raise_argument_error('hmget') if fields.empty? data_type_check(key, Hash) fields.flatten.map do |field| field = field.to_s if data[key] data[key][field] else nil end end end def hlen(key) data_type_check(key, Hash) return 0 unless data[key] data[key].size end def hvals(key) data_type_check(key, Hash) return [] unless data[key] data[key].values end def hincrby(key, field, increment) data_type_check(key, Hash) field = field.to_s if data[key] data[key][field] = (data[key][field].to_i + increment.to_i).to_s else data[key] = { field => increment.to_s } end data[key][field].to_i end def hincrbyfloat(key, field, increment) data_type_check(key, Hash) field = field.to_s if data[key] data[key][field] = (data[key][field].to_f + increment.to_f).to_s else data[key] = { field => increment.to_s } end data[key][field] end def hexists(key, field) data_type_check(key, Hash) return false unless data[key] data[key].key?(field.to_s) end def sync ; end def [](key) get(key) end def []=(key, value) set(key, value) end def set(key, value, *array_options) option_nx = array_options.delete("NX") option_xx = array_options.delete("XX") return false if option_nx && option_xx return false if option_nx && exists(key) return false if option_xx && !exists(key) data[key] = value.to_s options = Hash[array_options.each_slice(2).to_a] ttl_in_seconds = options["EX"] if options["EX"] ttl_in_seconds = options["PX"] / 1000.0 if options["PX"] expire(key, ttl_in_seconds) if ttl_in_seconds "OK" end def setbit(key, offset, bit) old_val = data[key] ? data[key].unpack('B*')[0].split("") : [] size_increment = [((offset/8)+1)*8-old_val.length, 0].max old_val += Array.new(size_increment).map{"0"} original_val = old_val[offset].to_i old_val[offset] = bit.to_s new_val = "" old_val.each_slice(8){|b| new_val = new_val + b.join("").to_i(2).chr } data[key] = new_val original_val end def setex(key, seconds, value) data[key] = value.to_s expire(key, seconds) "OK" end def setrange(key, offset, value) return unless data[key] s = data[key][offset,value.size] data[key][s] = value end def mset(*pairs) # Handle pairs for mapped_mset command pairs = pairs[0] if mapped_param?(pairs) raise_argument_error('mset') if pairs.empty? || pairs.size == 1 # We have to reply with a different error message here to be consistent with redis-rb 3.0.6 / redis-server 2.8.1 raise_argument_error("mset", "mset_odd") if pairs.size.odd? pairs.each_slice(2) do |pair| data[pair[0].to_s] = pair[1].to_s end "OK" end def msetnx(*pairs) # Handle pairs for mapped_msetnx command pairs = pairs[0] if mapped_param?(pairs) keys = [] pairs.each_with_index{|item, index| keys << item.to_s if index % 2 == 0} return false if keys.any?{|key| data.key?(key) } mset(*pairs) true end def incr(key) data.merge!({ key => (data[key].to_i + 1).to_s || "1"}) data[key].to_i end def incrby(key, by) data.merge!({ key => (data[key].to_i + by.to_i).to_s || by }) data[key].to_i end def decr(key) data.merge!({ key => (data[key].to_i - 1).to_s || "-1"}) data[key].to_i end def decrby(key, by) data.merge!({ key => ((data[key].to_i - by.to_i) || (by.to_i * -1)).to_s }) data[key].to_i end def type(key) case data[key] when nil then "none" when String then "string" when ZSet then "zset" when Hash then "hash" when Array then "list" when ::Set then "set" end end def quit ; end def shutdown; end def slaveof(host, port) ; end def scan(start_cursor, *args) match = "*" count = 10 if args.size.odd? raise_argument_error('scan') end if idx = args.index("MATCH") match = args[idx + 1] end if idx = args.index("COUNT") count = args[idx + 1] end start_cursor = start_cursor.to_i data_type_check(start_cursor, Fixnum) cursor = start_cursor next_keys = [] if start_cursor + count >= data.length next_keys = keys(match)[start_cursor..-1] cursor = 0 else cursor = start_cursor + 10 next_keys = keys(match)[start_cursor..cursor] end return "#{cursor}", next_keys end def zadd(key, *args) if !args.first.is_a?(Array) if args.size < 2 raise_argument_error('zadd') elsif args.size.odd? raise_syntax_error end else unless args.all? {|pair| pair.size == 2 } raise_syntax_error end end data_type_check(key, ZSet) data[key] ||= ZSet.new if args.size == 2 && !(Array === args.first) score, value = args exists = !data[key].key?(value.to_s) data[key][value.to_s] = score else # Turn [1, 2, 3, 4] into [[1, 2], [3, 4]] unless it is already args = args.each_slice(2).to_a unless args.first.is_a?(Array) exists = args.map(&:last).map { |el| data[key].key?(el.to_s) }.count(false) args.each { |s, v| data[key][v.to_s] = s } end exists end def zrem(key, value) data_type_check(key, ZSet) values = Array(value) return 0 unless data[key] response = values.map do |v| data[key].delete(v.to_s) if data[key].has_key?(v.to_s) end.compact.size remove_key_for_empty_collection(key) response end def zcard(key) data_type_check(key, ZSet) data[key] ? data[key].size : 0 end def zscore(key, value) data_type_check(key, ZSet) value = data[key] && data[key][value.to_s] value && value.to_s end def zcount(key, min, max) data_type_check(key, ZSet) return 0 unless data[key] data[key].select_by_score(min, max).size end def zincrby(key, num, value) data_type_check(key, ZSet) data[key] ||= ZSet.new data[key][value.to_s] ||= 0 data[key].increment(value.to_s, num) data[key][value.to_s].to_s end def zrank(key, value) data_type_check(key, ZSet) z = data[key] return unless z z.keys.sort_by {|k| z[k] }.index(value.to_s) end def zrevrank(key, value) data_type_check(key, ZSet) z = data[key] return unless z z.keys.sort_by {|k| -z[k] }.index(value.to_s) end def zrange(key, start, stop, with_scores = nil) data_type_check(key, ZSet) return [] unless data[key] # Sort by score, or if scores are equal, key alphanum results = data[key].sort do |(k1, v1), (k2, v2)| if v1 == v2 k1 <=> k2 else v1 <=> v2 end end # Select just the keys unless we want scores results = results.map(&:first) unless with_scores results[start..stop].flatten.map(&:to_s) end def zrevrange(key, start, stop, with_scores = nil) data_type_check(key, ZSet) return [] unless data[key] if with_scores data[key].sort_by {|_,v| -v } else data[key].keys.sort_by {|k| -data[key][k] } end[start..stop].flatten.map(&:to_s) end def zrangebyscore(key, min, max, *opts) data_type_check(key, ZSet) return [] unless data[key] range = data[key].select_by_score(min, max) vals = if opts.include?('WITHSCORES') range.sort_by {|_,v| v } else range.keys.sort_by {|k| range[k] } end limit = get_limit(opts, vals) vals = vals[*limit] if limit vals.flatten.map(&:to_s) end def zrevrangebyscore(key, max, min, *opts) opts = opts.flatten data_type_check(key, ZSet) return [] unless data[key] range = data[key].select_by_score(min, max) vals = if opts.include?('WITHSCORES') range.sort_by {|_,v| -v } else range.keys.sort_by {|k| -range[k] } end limit = get_limit(opts, vals) vals = vals[*limit] if limit vals.flatten.map(&:to_s) end def zremrangebyscore(key, min, max) data_type_check(key, ZSet) return 0 unless data[key] range = data[key].select_by_score(min, max) range.each {|k,_| data[key].delete(k) } range.size end def zremrangebyrank(key, start, stop) data_type_check(key, ZSet) return 0 unless data[key] sorted_elements = data[key].sort_by { |k, v| v } start = sorted_elements.length if start > sorted_elements.length elements_to_delete = sorted_elements[start..stop] elements_to_delete.each { |elem, rank| data[key].delete(elem) } elements_to_delete.size end def zinterstore(out, *args) data_type_check(out, ZSet) args_handler = SortedSetArgumentHandler.new(args) data[out] = SortedSetIntersectStore.new(args_handler, data).call data[out].size end def zunionstore(out, *args) data_type_check(out, ZSet) args_handler = SortedSetArgumentHandler.new(args) data[out] = SortedSetUnionStore.new(args_handler, data).call data[out].size end private def raise_argument_error(command, match_string=command) error_message = if %w(hmset mset_odd).include?(match_string.downcase) "ERR wrong number of arguments for #{command.upcase}" else "ERR wrong number of arguments for '#{command}' command" end raise Redis::CommandError, error_message end def raise_syntax_error raise Redis::CommandError, "ERR syntax error" end def remove_key_for_empty_collection(key) del(key) if data[key] && data[key].empty? end def data_type_check(key, klass) if data[key] && !data[key].is_a?(klass) warn "Operation against a key holding the wrong kind of value: Expected #{klass} at #{key}." raise Redis::CommandError.new("WRONGTYPE Operation against a key holding the wrong kind of value") end end def get_limit(opts, vals) index = opts.index('LIMIT') if index offset = opts[index + 1] count = opts[index + 2] count = vals.size if count < 0 [offset, count] end end def mapped_param? param param.size == 1 && param[0].is_a?(Array) end def srandmember_single(key) data_type_check(key, ::Set) return nil unless data[key] data[key].to_a[rand(data[key].size)] end def srandmember_multiple(key, number) return [] unless data[key] if number >= 0 # replace with `data[key].to_a.sample(number)` when 1.8.7 is deprecated (1..number).inject([]) do |selected, _| available_elements = data[key].to_a - selected selected << available_elements[rand(available_elements.size)] end.compact else (1..-number).map { data[key].to_a[rand(data[key].size)] }.flatten end end end end end Redis::Connection.drivers << Redis::Connection::Memory ruby-fakeredis-0.5.0/lib/fakeredis.rb0000644000175000017500000000013212616117431017604 0ustar abhijithabhijithrequire 'redis' require 'redis/connection/memory' module FakeRedis Redis = ::Redis end ruby-fakeredis-0.5.0/lib/fakeredis/0000755000175000017500000000000012616117431017263 5ustar abhijithabhijithruby-fakeredis-0.5.0/lib/fakeredis/rspec.rb0000644000175000017500000000062712616117431020731 0ustar abhijithabhijith# Require this either in your Gemfile or in RSpec's # support scripts. Examples: # # # Gemfile # group :test do # gem "rspec" # gem "fakeredis", :require => "fakeredis/rspec" # end # # # spec/support/fakeredis.rb # require 'fakeredis/rspec' # require 'rspec/core' require 'fakeredis' RSpec.configure do |c| c.before do Redis::Connection::Memory.reset_all_databases end end ruby-fakeredis-0.5.0/lib/fakeredis/command_executor.rb0000644000175000017500000000107712616117431023151 0ustar abhijithabhijithmodule FakeRedis module CommandExecutor def write(command) meffod = command.shift.to_s.downcase.to_sym if in_multi && !(TRANSACTION_COMMANDS.include? meffod) # queue commands queued_commands << [meffod, *command] reply = 'QUEUED' elsif respond_to?(meffod) reply = send(meffod, *command) else raise Redis::CommandError, "ERR unknown command '#{meffod}'" end if reply == true reply = 1 elsif reply == false reply = 0 end replies << reply nil end end end ruby-fakeredis-0.5.0/lib/fakeredis/sorted_set_store.rb0000644000175000017500000000400312616117431023174 0ustar abhijithabhijithmodule FakeRedis class SortedSetStore attr_accessor :data, :weights, :aggregate, :keys def initialize params, data self.data = data self.weights = params.weights self.aggregate = params.aggregate self.keys = params.keys end def hashes @hashes ||= keys.map do |src| case data[src] when ::Set # Every value has a score of 1 Hash[data[src].map {|k,v| [k, 1]}] when Hash data[src] else {} end end end # Apply the weightings to the hashes def computed_values unless defined?(@computed_values) && @computed_values # Do nothing if all weights are 1, as n * 1 is n @computed_values = hashes if weights.all? {|weight| weight == 1 } # Otherwise, multiply the values in each hash by that hash's weighting @computed_values ||= hashes.each_with_index.map do |hash, index| weight = weights[index] Hash[hash.map {|k, v| [k, (v * weight)]}] end end @computed_values end def aggregate_sum out selected_keys.each do |key| out[key] = computed_values.inject(0) do |n, hash| n + (hash[key] || 0) end end end def aggregate_min out selected_keys.each do |key| out[key] = computed_values.map {|h| h[key] }.compact.min end end def aggregate_max out selected_keys.each do |key| out[key] = computed_values.map {|h| h[key] }.compact.max end end def selected_keys raise NotImplemented, "subclass needs to implement #selected_keys" end def call ZSet.new.tap {|out| send("aggregate_#{aggregate}", out) } end end class SortedSetIntersectStore < SortedSetStore def selected_keys @values ||= hashes.inject([]) { |r, h| r.empty? ? h.keys : (r & h.keys) } end end class SortedSetUnionStore < SortedSetStore def selected_keys @values ||= hashes.map(&:keys).flatten.uniq end end end ruby-fakeredis-0.5.0/lib/fakeredis/zset.rb0000644000175000017500000000130612616117431020575 0ustar abhijithabhijithmodule FakeRedis class ZSet < Hash def []=(key, val) super(key, _floatify(val)) end # Increments the value of key by val def increment(key, val) self[key] += _floatify(val) end def select_by_score min, max min = _floatify(min, true) max = _floatify(max, false) reject {|_,v| v < min || v > max } end private # Originally lifted from redis-rb def _floatify(str, increment = true) if (( inf = str.to_s.match(/^([+-])?inf/i) )) (inf[1] == "-" ? -1.0 : 1.0) / 0.0 elsif (( number = str.to_s.match(/^\((\d+)/i) )) number[1].to_i + (increment ? 1 : -1) else Float str end end end end ruby-fakeredis-0.5.0/lib/fakeredis/transaction_commands.rb0000644000175000017500000000317112616117431024020 0ustar abhijithabhijithmodule FakeRedis TRANSACTION_COMMANDS = [:discard, :exec, :multi, :watch, :unwatch] module TransactionCommands def self.included(klass) klass.class_eval do def self.queued_commands @queued_commands ||= Hash.new {|h,k| h[k] = [] } end def self.in_multi @in_multi ||= Hash.new{|h,k| h[k] = false} end def queued_commands self.class.queued_commands[database_instance_key] end def queued_commands=(cmds) self.class.queued_commands[database_instance_key] = cmds end def in_multi self.class.in_multi[database_instance_key] end def in_multi=(multi_state) self.class.in_multi[database_instance_key] = multi_state end end end def discard unless in_multi raise Redis::CommandError, "ERR DISCARD without MULTI" end self.in_multi = false self.queued_commands = [] 'OK' end def exec unless in_multi raise Redis::CommandError, "ERR EXEC without MULTI" end responses = queued_commands.map do |cmd| begin send(*cmd) rescue => e e end end self.queued_commands = [] # reset queued_commands self.in_multi = false # reset in_multi state responses end def multi if in_multi raise Redis::CommandError, "ERR MULTI calls can not be nested" end self.in_multi = true yield(self) if block_given? "OK" end def watch(_) "OK" end def unwatch "OK" end end end ruby-fakeredis-0.5.0/lib/fakeredis/sorted_set_argument_handler.rb0000644000175000017500000000475012616117431025370 0ustar abhijithabhijithmodule FakeRedis # Takes in the variable length array of arguments for a zinterstore/zunionstore method # and parses them into a few attributes for the method to access. # # Handles throwing errors for various scenarios (matches redis): # * Custom weights specified, but not enough or too many given # * Invalid aggregate value given # * Multiple aggregate values given class SortedSetArgumentHandler # [Symbol] The aggregate method to use for the output values. One of %w(sum min max) expected attr_reader :aggregate # [Integer] Number of keys in the argument list attr_accessor :number_of_keys # [Array] The actual keys in the argument list attr_accessor :keys # [Array] integers for weighting the values of each key - one number per key expected attr_accessor :weights # Used internally attr_accessor :type # Expects all the argments for the method to be passed as an array def initialize args # Pull out known lengths of data self.number_of_keys = args.shift self.keys = args.shift(number_of_keys) # Handle the variable lengths of data (WEIGHTS/AGGREGATE) args.inject(self) {|handler, item| handler.handle(item) } # Defaults for unspecified things self.weights ||= Array.new(number_of_keys) { 1 } self.aggregate ||= :sum # Validate values raise(Redis::CommandError, "ERR syntax error") unless weights.size == number_of_keys raise(Redis::CommandError, "ERR syntax error") unless [:min, :max, :sum].include?(aggregate) end # Only allows assigning a value *once* - raises Redis::CommandError if a second is given def aggregate=(str) raise(Redis::CommandError, "ERR syntax error") if (defined?(@aggregate) && @aggregate) @aggregate = str.to_s.downcase.to_sym end # Decides how to handle an item, depending on where we are in the arguments def handle(item) case item when "WEIGHTS" self.type = :weights self.weights = [] when "AGGREGATE" self.type = :aggregate when nil # This should never be called, raise a syntax error if we manage to hit it raise(Redis::CommandError, "ERR syntax error") else send "handle_#{type}", item end self end def handle_weights(item) self.weights << item end def handle_aggregate(item) self.aggregate = item end def inject_block lambda { |handler, item| handler.handle(item) } end end end ruby-fakeredis-0.5.0/lib/fakeredis/expiring_hash.rb0000644000175000017500000000225112616117431022440 0ustar abhijithabhijithmodule FakeRedis # Represents a normal hash with some additional expiration information # associated with each key class ExpiringHash < Hash attr_reader :expires def initialize(*) super @expires = {} end def [](key) key = normalize key delete(key) if expired?(key) super end def []=(key, val) key = normalize key expire(key) super end def delete(key) key = normalize key expire(key) super end def expire(key) key = normalize key expires.delete(key) end def expired?(key) key = normalize key expires.include?(key) && expires[key] < Time.now end def key?(key) key = normalize key delete(key) if expired?(key) super end def values_at(*keys) keys.each do |key| key = normalize(key) delete(key) if expired?(key) end super end def keys super.select do |key| key = normalize(key) if expired?(key) delete(key) false else true end end end def normalize key key.to_s end end end ruby-fakeredis-0.5.0/lib/fakeredis/sort_method.rb0000644000175000017500000000642012616117431022141 0ustar abhijithabhijith# Codes are mostly referenced from MockRedis' implementation. module FakeRedis module SortMethod def sort(key, *redis_options_array) return [] unless key unless %w(list set zset).include? type(key) warn "Operation against a key holding the wrong kind of value: Expected list, set or zset at #{key}." raise Redis::CommandError.new("WRONGTYPE Operation against a key holding the wrong kind of value") end # redis_options is an array of format [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination] # Lets nibble it back into a hash options = extract_options_from(redis_options_array) # And now to actually do the work of this method projected = project(data[key], options[:by], options[:get]) sorted = sort_by(projected, options[:order]) sliced = slice(sorted, options[:limit]) # We have to flatten it down as redis-rb adds back the array to the return value result = sliced.flatten(1) options[:store] ? rpush(options[:store], sliced) : sliced.flatten(1) end private ASCENDING_SORT = Proc.new { |a, b| a.first <=> b.first } DESCENDING_SORT = Proc.new { |a, b| b.first <=> a.first } def extract_options_from(options_array) # Defaults options = { :limit => [], :order => "ASC", :get => [] } if options_array.first == "BY" options_array.shift options[:by] = options_array.shift end if options_array.first == "LIMIT" options_array.shift options[:limit] = [options_array.shift, options_array.shift] end while options_array.first == "GET" options_array.shift options[:get] << options_array.shift end if %w(ASC DESC ALPHA).include?(options_array.first) options[:order] = options_array.shift options[:order] = "ASC" if options[:order] == "ALPHA" end if options_array.first == "STORE" options_array.shift options[:store] = options_array.shift end options end def project(enumerable, by, get_patterns) enumerable.map do |*elements| element = elements.flatten.first weight = by ? lookup_from_pattern(by, element) : element value = element if get_patterns.length > 0 value = get_patterns.map do |pattern| pattern == "#" ? element : lookup_from_pattern(pattern, element) end value = value.first if value.length == 1 end [weight, value] end end def sort_by(projected, direction) sorter = case direction.upcase when "DESC" DESCENDING_SORT when "ASC", "ALPHA" ASCENDING_SORT else raise "Invalid direction '#{direction}'" end projected.sort(&sorter).map(&:last) end def slice(sorted, limit) skip = limit.first || 0 take = limit.last || sorted.length sorted[skip...(skip + take)] || sorted end def lookup_from_pattern(pattern, element) key = pattern.sub('*', element) if (hash_parts = key.split('->')).length > 1 hget hash_parts.first, hash_parts.last else get key end end end end ruby-fakeredis-0.5.0/lib/fakeredis/version.rb0000644000175000017500000000005112616117431021271 0ustar abhijithabhijithmodule FakeRedis VERSION = "0.5.0" end ruby-fakeredis-0.5.0/lib/fake_redis.rb0000644000175000017500000000002412616117431017743 0ustar abhijithabhijithrequire "fakeredis" ruby-fakeredis-0.5.0/LICENSE0000644000175000017500000000205312616117431015565 0ustar abhijithabhijithCopyright (c) 2011-2014 Guillermo Iguaran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ruby-fakeredis-0.5.0/fakeredis.gemspec0000644000175000017500000000164112616117431020064 0ustar abhijithabhijith# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "fakeredis/version" Gem::Specification.new do |s| s.name = "fakeredis" s.version = FakeRedis::VERSION s.platform = Gem::Platform::RUBY s.authors = ["Guillermo Iguaran"] s.email = ["guilleiguaran@gmail.com"] s.homepage = "https://guilleiguaran.github.com/fakeredis" s.license = "MIT" s.summary = %q{Fake (In-memory) driver for redis-rb.} s.description = %q{Fake (In-memory) driver for redis-rb. Useful for testing environment and machines without Redis.} s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] s.add_runtime_dependency(%q, ["~> 3.0"]) s.add_development_dependency(%q, ["~> 3.0"]) end ruby-fakeredis-0.5.0/spec/0000755000175000017500000000000012616117431015512 5ustar abhijithabhijithruby-fakeredis-0.5.0/spec/keys_spec.rb0000644000175000017500000002507012616117431020030 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe "KeysMethods" do before(:each) do @client = Redis.new end it "should delete a key" do @client.set("key1", "1") @client.set("key2", "2") @client.del("key1", "key2") @client.get("key1").should be == nil end it "should delete multiple keys" do @client.set("key1", "1") @client.set("key2", "2") @client.del(["key1", "key2"]) @client.get("key1").should be == nil @client.get("key2").should be == nil end it "should error deleting no keys" do lambda { @client.del }.should raise_error(Redis::CommandError, "ERR wrong number of arguments for 'del' command") lambda { @client.del [] }.should raise_error(Redis::CommandError, "ERR wrong number of arguments for 'del' command") end it "should return true when setting expires on keys that exist" do @client.set("key1", "1") @client.expire("key1", 1).should == true end it "should return false when attempting to set expires on a key that does not exist" do @client.expire("key1", 1).should == false end it "should determine if a key exists" do @client.set("key1", "1") @client.exists("key1").should be == true @client.exists("key2").should be == false end it "should set a key's time to live in seconds" do @client.set("key1", "1") @client.expire("key1", 1) @client.ttl("key1").should be == 1 end it "should set the expiration for a key as a UNIX timestamp" do @client.set("key1", "1") @client.expireat("key1", Time.now.to_i + 2) @client.ttl("key1").should be == 2 end it "should not have an expiration after re-set" do @client.set("key1", "1") @client.expireat("key1", Time.now.to_i + 2) @client.set("key1", "1") @client.ttl("key1").should be == -1 end it "should not have a ttl if expired (and thus key does not exist)" do @client.set("key1", "1") @client.expireat("key1", Time.now.to_i) @client.ttl("key1").should be == -2 end it "should not find a key if expired" do @client.set("key1", "1") @client.expireat("key1", Time.now.to_i) @client.get("key1").should be_nil end it "should not find multiple keys if expired" do @client.set("key1", "1") @client.set("key2", "2") @client.expireat("key1", Time.now.to_i) @client.mget("key1", "key2").should be == [nil, "2"] end it "should only find keys that aren't expired" do @client.set("key1", "1") @client.set("key2", "2") @client.expireat("key1", Time.now.to_i) @client.keys.should be == ["key2"] end it "should not exist if expired" do @client.set("key1", "1") @client.expireat("key1", Time.now.to_i) @client.exists("key1").should be false end it "should find all keys matching the given pattern" do @client.set("key:a", "1") @client.set("key:b", "2") @client.set("key:c", "3") @client.set("akeyd", "4") @client.set("key1", "5") @client.mset("database", 1, "above", 2, "suitability", 3, "able", 4) @client.keys("key:*").should =~ ["key:a", "key:b", "key:c"] @client.keys("ab*").should =~ ["above", "able"] end it "should remove the expiration from a key" do @client.set("key1", "1") @client.expireat("key1", Time.now.to_i + 1) @client.persist("key1").should be == true @client.persist("key1").should be == false @client.ttl("key1").should be == -1 end it "should return a random key from the keyspace" do @client.set("key1", "1") @client.set("key2", "2") ["key1", "key2"].include?(@client.randomkey).should be == true end it "should rename a key" do @client.set("key1", "2") @client.rename("key1", "key2") @client.get("key1").should be == nil @client.get("key2").should be == "2" end it "should rename a key, only if new key does not exist" do @client.set("key1", "1") @client.set("key2", "2") @client.set("key3", "3") @client.renamenx("key1", "key2") @client.renamenx("key3", "key4") @client.get("key1").should be == "1" @client.get("key2").should be == "2" @client.get("key3").should be == nil @client.get("key4").should be == "3" end it "should determine the type stored at key" do # Non-existing key @client.type("key0").should be == "none" # String @client.set("key1", "1") @client.type("key1").should be == "string" # List @client.lpush("key2", "1") @client.type("key2").should be == "list" # Set @client.sadd("key3", "1") @client.type("key3").should be == "set" # Sorted Set @client.zadd("key4", 1.0, "1") @client.type("key4").should be == "zset" # Hash @client.hset("key5", "a", "1") @client.type("key5").should be == "hash" end it "should convert the value into a string before storing" do @client.set("key1", 1) @client.get("key1").should be == "1" @client.setex("key2", 30, 1) @client.get("key2").should be == "1" @client.getset("key3", 1) @client.get("key3").should be == "1" end it "should return 'OK' for the setex command" do @client.setex("key4", 30, 1).should be == "OK" end it "should convert the key into a string before storing" do @client.set(123, "foo") @client.keys.should include("123") @client.get("123").should be == "foo" @client.setex(456, 30, "foo") @client.keys.should include("456") @client.get("456").should be == "foo" @client.getset(789, "foo") @client.keys.should include("789") @client.get("789").should be == "foo" end it "should only operate against keys containing string values" do @client.sadd("key1", "one") lambda { @client.get("key1") }.should raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value") lambda { @client.getset("key1", 1) }.should raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value") @client.hset("key2", "one", "two") lambda { @client.get("key2") }.should raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value") lambda { @client.getset("key2", 1) }.should raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value") end it "should move a key from one database to another successfully" do @client.select(0) @client.set("key1", "1") @client.move("key1", 1).should be == true @client.select(0) @client.get("key1").should be_nil @client.select(1) @client.get("key1").should be == "1" end it "should fail to move a key that does not exist in the source database" do @client.select(0) @client.get("key1").should be_nil @client.move("key1", 1).should be == false @client.select(0) @client.get("key1").should be_nil @client.select(1) @client.get("key1").should be_nil end it "should fail to move a key that exists in the destination database" do @client.select(0) @client.set("key1", "1") @client.select(1) @client.set("key1", "2") @client.select(0) @client.move("key1", 1).should be == false @client.select(0) @client.get("key1").should be == "1" @client.select(1) @client.get("key1").should be == "2" end it "should fail to move a key to the same database" do @client.select(0) @client.set("key1", "1") lambda { @client.move("key1", 0) }.should raise_error(Redis::CommandError, "ERR source and destination objects are the same") @client.select(0) @client.get("key1").should be == "1" end it "should scan all keys in the database" do 100.times do |x| @client.set("key#{x}", "#{x}") end cursor = 0 all_keys = [] loop { cursor, keys = @client.scan(cursor) all_keys += keys break if cursor == "0" } all_keys.uniq.size.should == 100 all_keys[0].should =~ /key\d+/ end it "should match keys to a pattern when scanning" do 50.times do |x| @client.set("key#{x}", "#{x}") end @client.set("miss_me", 1) @client.set("pass_me", 2) cursor = 0 all_keys = [] loop { cursor, keys = @client.scan(cursor, :match => "key*") all_keys += keys break if cursor == "0" } all_keys.uniq.size.should == 50 end it "should specify doing more work when scanning" do 100.times do |x| @client.set("key#{x}", "#{x}") end cursor, all_keys = @client.scan(cursor, :count => 100) cursor.should == "0" all_keys.uniq.size.should == 100 end context "with extended options" do it "uses ex option to set the expire time, in seconds" do ttl = 7 @client.set("key1", "1", { :ex => ttl }).should == "OK" @client.ttl("key1").should == ttl end it "uses px option to set the expire time, in miliseconds" do ttl = 7000 @client.set("key1", "1", { :px => ttl }).should == "OK" @client.ttl("key1").should == (ttl / 1000) end # Note that the redis-rb implementation will always give PX last. # Redis seems to process each expiration option and the last one wins. it "prefers the finer-grained PX expiration option over EX" do ttl_px = 6000 ttl_ex = 10 @client.set("key1", "1", { :px => ttl_px, :ex => ttl_ex }) @client.ttl("key1").should == (ttl_px / 1000) @client.set("key1", "1", { :ex => ttl_ex, :px => ttl_px }) @client.ttl("key1").should == (ttl_px / 1000) end it "uses nx option to only set the key if it does not already exist" do @client.set("key1", "1", { :nx => true }).should == true @client.set("key1", "2", { :nx => true }).should == false @client.get("key1").should == "1" end it "uses xx option to only set the key if it already exists" do @client.set("key2", "1", { :xx => true }).should == false @client.set("key2", "2") @client.set("key2", "1", { :xx => true }).should == true @client.get("key2").should == "1" end it "does not set the key if both xx and nx option are specified" do @client.set("key2", "1", { :nx => true, :xx => true }).should == false @client.get("key2").should be_nil end end end end ruby-fakeredis-0.5.0/spec/sets_spec.rb0000644000175000017500000002041112616117431020025 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe "SetsMethods" do before(:each) do @client = Redis.new end it "should add a member to a set" do @client.sadd("key", "value").should be == true @client.sadd("key", "value").should be == false @client.smembers("key").should be == ["value"] end it "should raise error if command arguments count is not enough" do expect { @client.sadd("key", []) }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for 'sadd' command") expect { @client.sinter(*[]) }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for 'sinter' command") @client.smembers("key").should be_empty end it "should add multiple members to a set" do @client.sadd("key", %w(value other something more)).should be == 4 @client.sadd("key", %w(and additional values)).should be == 3 @client.smembers("key").should =~ ["value", "other", "something", "more", "and", "additional", "values"] end it "should get the number of members in a set" do @client.sadd("key", "val1") @client.sadd("key", "val2") @client.scard("key").should be == 2 end it "should subtract multiple sets" do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.sadd("key1", "c") @client.sadd("key1", "d") @client.sadd("key2", "c") @client.sadd("key3", "a") @client.sadd("key3", "c") @client.sadd("key3", "e") @client.sdiff("key1", "key2", "key3").should =~ ["b", "d"] end it "should subtract from a nonexistent set" do @client.sadd("key2", "a") @client.sadd("key2", "b") @client.sdiff("key1", "key2").should == [] end it "should subtract multiple sets and store the resulting set in a key" do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.sadd("key1", "c") @client.sadd("key1", "d") @client.sadd("key2", "c") @client.sadd("key3", "a") @client.sadd("key3", "c") @client.sadd("key3", "e") @client.sdiffstore("key", "key1", "key2", "key3") @client.smembers("key").should =~ ["b", "d"] end it "should intersect multiple sets" do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.sadd("key1", "c") @client.sadd("key1", "d") @client.sadd("key2", "c") @client.sadd("key3", "a") @client.sadd("key3", "c") @client.sadd("key3", "e") @client.sinter("key1", "key2", "key3").should be == ["c"] end it "should intersect multiple sets and store the resulting set in a key" do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.sadd("key1", "c") @client.sadd("key1", "d") @client.sadd("key2", "c") @client.sadd("key3", "a") @client.sadd("key3", "c") @client.sadd("key3", "e") @client.sinterstore("key", "key1", "key2", "key3") @client.smembers("key").should be == ["c"] end it "should determine if a given value is a member of a set" do @client.sadd("key1", "a") @client.sismember("key1", "a").should be == true @client.sismember("key1", "b").should be == false @client.sismember("key2", "a").should be == false end it "should get all the members in a set" do @client.sadd("key", "a") @client.sadd("key", "b") @client.sadd("key", "c") @client.sadd("key", "d") @client.smembers("key").should =~ ["a", "b", "c", "d"] end it "should move a member from one set to another" do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.sadd("key2", "c") @client.smove("key1", "key2", "a").should be == true @client.smove("key1", "key2", "a").should be == false @client.smembers("key1").should be == ["b"] @client.smembers("key2").should =~ ["c", "a"] end it "should remove and return a random member from a set" do @client.sadd("key1", "a") @client.sadd("key1", "b") ["a", "b"].include?(@client.spop("key1")).should be true ["a", "b"].include?(@client.spop("key1")).should be true @client.spop("key1").should be_nil end it "should get a random member from a set" do @client.sadd("key1", "a") @client.sadd("key1", "b") ["a", "b"].include?(@client.spop("key1")).should be true end it "should remove a member from a set" do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.srem("key1", "a").should be == true @client.srem("key1", "a").should be == false @client.smembers("key1").should be == ["b"] end it "should remove multiple members from a set" do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.srem("key1", [ "a", "b"]).should == 2 @client.smembers("key1").should be_empty end it "should remove the set's key once it's empty" do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.srem("key1", "b") @client.srem("key1", "a") @client.exists("key1").should be == false end it "should add multiple sets" do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.sadd("key1", "c") @client.sadd("key1", "d") @client.sadd("key2", "c") @client.sadd("key3", "a") @client.sadd("key3", "c") @client.sadd("key3", "e") @client.sunion("key1", "key2", "key3").should =~ ["a", "b", "c", "d", "e"] end it "should add multiple sets and store the resulting set in a key" do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.sadd("key1", "c") @client.sadd("key1", "d") @client.sadd("key2", "c") @client.sadd("key3", "a") @client.sadd("key3", "c") @client.sadd("key3", "e") @client.sunionstore("key", "key1", "key2", "key3") @client.smembers("key").should =~ ["a", "b", "c", "d", "e"] end end describe 'srandmember' do before(:each) do @client = Redis.new end context 'with a set that has three elements' do before do @client.sadd("key1", "a") @client.sadd("key1", "b") @client.sadd("key1", "c") end context 'when called without the optional number parameter' do it 'is a random element from the set' do random_element = @client.srandmember("key1") ['a', 'b', 'c'].include?(random_element).should be true end end context 'when called with the optional number parameter of 1' do it 'is an array of one random element from the set' do random_elements = @client.srandmember("key1", 1) [['a'], ['b'], ['c']].include?(@client.srandmember("key1", 1)).should be true end end context 'when called with the optional number parameter of 2' do it 'is an array of two unique, random elements from the set' do random_elements = @client.srandmember("key1", 2) random_elements.count.should == 2 random_elements.uniq.count.should == 2 random_elements.all? do |element| ['a', 'b', 'c'].include?(element).should be true end end end context 'when called with an optional parameter of -100' do it 'is an array of 100 random elements from the set, some of which are repeated' do random_elements = @client.srandmember("key1", -100) random_elements.count.should == 100 random_elements.uniq.count.should <= 3 random_elements.all? do |element| ['a', 'b', 'c'].include?(element).should be true end end end context 'when called with an optional parameter of 100' do it 'is an array of all of the elements from the set, none of which are repeated' do random_elements = @client.srandmember("key1", 100) random_elements.count.should == 3 random_elements.uniq.count.should == 3 random_elements.should =~ ['a', 'b', 'c'] end end end context 'with an empty set' do before { @client.del("key1") } it 'is nil without the extra parameter' do @client.srandmember("key1").should be_nil end it 'is an empty array with an extra parameter' do @client.srandmember("key1", 1).should == [] end end end end ruby-fakeredis-0.5.0/spec/strings_spec.rb0000644000175000017500000002221612616117431020545 0ustar abhijithabhijith# encoding: UTF-8 require 'spec_helper' module FakeRedis describe "StringsMethods" do before(:each) do @client = Redis.new end it "should append a value to key" do @client.set("key1", "Hello") @client.append("key1", " World") @client.get("key1").should be == "Hello World" end it "should decrement the integer value of a key by one" do @client.set("counter", "1") @client.decr("counter") @client.get("counter").should be == "0" end it "should decrement the integer value of a key by the given number" do @client.set("counter", "10") @client.decrby("counter", "5") @client.get("counter").should be == "5" end it "should get the value of a key" do @client.get("key2").should be == nil end it "should returns the bit value at offset in the string value stored at key" do @client.set("key1", "a") @client.getbit("key1", 1).should be == 1 @client.getbit("key1", 2).should be == 1 @client.getbit("key1", 3).should be == 0 @client.getbit("key1", 4).should be == 0 @client.getbit("key1", 5).should be == 0 @client.getbit("key1", 6).should be == 0 @client.getbit("key1", 7).should be == 1 end it "should allow direct bit manipulation even if the string isn't set" do @client.setbit("key1", 10, 1) @client.getbit("key1", 10).should be == 1 end context 'when a bit is previously set to 0' do before { @client.setbit("key1", 10, 0) } it 'setting it to 1 returns 0' do expect(@client.setbit("key1", 10, 1)).to eql 0 end it 'setting it to 0 returns 0' do expect(@client.setbit("key1", 10, 0)).to eql 0 end end context 'when a bit is previously set to 1' do before { @client.setbit("key1", 10, 1) } it 'setting it to 0 returns 1' do expect(@client.setbit("key1", 10, 0)).to eql 1 end it 'setting it to 1 returns 1' do expect(@client.setbit("key1", 10, 1)).to eql 1 end end it "should get a substring of the string stored at a key" do @client.set("key1", "This a message") @client.getrange("key1", 0, 3).should be == "This" @client.substr("key1", 0, 3).should be == "This" end it "should set the string value of a key and return its old value" do @client.set("key1","value1") @client.getset("key1", "value2").should be == "value1" @client.get("key1").should be == "value2" end it "should return nil for #getset if the key does not exist when setting" do @client.getset("key1", "value1").should be == nil @client.get("key1").should be == "value1" end it "should increment the integer value of a key by one" do @client.set("counter", "1") @client.incr("counter").should be == 2 @client.get("counter").should be == "2" end it "should not change the expire value of the key during incr" do @client.set("counter", "1") @client.expire("counter", 600).should be true @client.ttl("counter").should be == 600 @client.incr("counter").should be == 2 @client.ttl("counter").should be == 600 end it "should decrement the integer value of a key by one" do @client.set("counter", "1") @client.decr("counter").should be == 0 @client.get("counter").should be == "0" end it "should not change the expire value of the key during decr" do @client.set("counter", "2") @client.expire("counter", 600).should be true @client.ttl("counter").should be == 600 @client.decr("counter").should be == 1 @client.ttl("counter").should be == 600 end it "should increment the integer value of a key by the given number" do @client.set("counter", "10") @client.incrby("counter", "5").should be == 15 @client.incrby("counter", 2).should be == 17 @client.get("counter").should be == "17" end it "should not change the expire value of the key during incrby" do @client.set("counter", "1") @client.expire("counter", 600).should be true @client.ttl("counter").should be == 600 @client.incrby("counter", "5").should be == 6 @client.ttl("counter").should be == 600 end it "should decrement the integer value of a key by the given number" do @client.set("counter", "10") @client.decrby("counter", "5").should be == 5 @client.decrby("counter", 2).should be == 3 @client.get("counter").should be == "3" end it "should not change the expire value of the key during decrby" do @client.set("counter", "8") @client.expire("counter", 600).should be true @client.ttl("counter").should be == 600 @client.decrby("counter", "3").should be == 5 @client.ttl("counter").should be == 600 end it "should get the values of all the given keys" do @client.set("key1", "value1") @client.set("key2", "value2") @client.set("key3", "value3") @client.mget("key1", "key2", "key3").should be == ["value1", "value2", "value3"] @client.mget(["key1", "key2", "key3"]).should be == ["value1", "value2", "value3"] end it "returns nil for non existent keys" do @client.set("key1", "value1") @client.set("key3", "value3") @client.mget("key1", "key2", "key3", "key4").should be == ["value1", nil, "value3", nil] @client.mget(["key1", "key2", "key3", "key4"]).should be == ["value1", nil, "value3", nil] end it 'raises an argument error when not passed any fields' do @client.set("key3", "value3") lambda { @client.mget }.should raise_error(Redis::CommandError) end it "should set multiple keys to multiple values" do @client.mset(:key1, "value1", :key2, "value2") @client.get("key1").should be == "value1" @client.get("key2").should be == "value2" end it "should raise error if command arguments count is wrong" do expect { @client.mset }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for 'mset' command") expect { @client.mset(:key1) }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for 'mset' command") expect { @client.mset(:key1, "value", :key2) }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for MSET") @client.get("key1").should be_nil @client.get("key2").should be_nil end it "should set multiple keys to multiple values, only if none of the keys exist" do @client.msetnx(:key1, "value1", :key2, "value2").should be == true @client.msetnx(:key1, "value3", :key2, "value4").should be == false @client.get("key1").should be == "value1" @client.get("key2").should be == "value2" end it "should set multiple keys to multiple values with a hash" do @client.mapped_mset(:key1 => "value1", :key2 => "value2") @client.get("key1").should be == "value1" @client.get("key2").should be == "value2" end it "should set multiple keys to multiple values with a hash, only if none of the keys exist" do @client.mapped_msetnx(:key1 => "value1", :key2 => "value2").should be == true @client.mapped_msetnx(:key1 => "value3", :key2 => "value4").should be == false @client.get("key1").should be == "value1" @client.get("key2").should be == "value2" end it "should set the string value of a key" do @client.set("key1", "1") @client.get("key1").should be == "1" end it "should sets or clears the bit at offset in the string value stored at key" do @client.set("key1", "abc") @client.setbit("key1", 11, 1) @client.get("key1").should be == "arc" end it "should set the value and expiration of a key" do @client.setex("key1", 30, "value1") @client.get("key1").should be == "value1" @client.ttl("key1").should be == 30 end it "should set the value of a key, only if the key does not exist" do @client.set("key1", "test value") @client.setnx("key1", "new value") @client.setnx("key2", "another value") @client.get("key1").should be == "test value" @client.get("key2").should be == "another value" end it "should overwrite part of a string at key starting at the specified offset" do @client.set("key1", "Hello World") @client.setrange("key1", 6, "Redis") @client.get("key1").should be == "Hello Redis" end it "should get the length of the value stored in a key" do @client.set("key1", "abc") @client.strlen("key1").should be == 3 end it "should return 0 bits when there's no key" do @client.bitcount("key1").should be == 0 end it "should count the number of bits of a string" do @client.set("key1", "foobar") @client.bitcount("key1").should be == 26 end it "should count correctly with UTF-8 strings" do @client.set("key1", '判') @client.bitcount("key1").should be == 10 end it "should count the number of bits of a string given a range" do @client.set("key1", "foobar") @client.bitcount("key1", 0, 0).should be == 4 @client.bitcount("key1", 1, 1).should be == 6 @client.bitcount("key1", 0, 1).should be == 10 end end end ruby-fakeredis-0.5.0/spec/support/0000755000175000017500000000000012616117431017226 5ustar abhijithabhijithruby-fakeredis-0.5.0/spec/support/shared_examples/0000755000175000017500000000000012616117431022372 5ustar abhijithabhijithruby-fakeredis-0.5.0/spec/support/shared_examples/sortable.rb0000644000175000017500000000426012616117431024534 0ustar abhijithabhijithshared_examples_for "a sortable" do it 'returns empty array on nil' do @client.sort(nil).should == [] end context 'ordering' do it 'orders ascending by default' do @client.sort(@key).should == ['1', '2'] end it 'orders by ascending when specified' do @client.sort(@key, :order => "ASC").should == ['1', '2'] end it 'orders by descending when specified' do @client.sort(@key, :order => "DESC").should == ['2', '1'] end it "orders by ascending when alpha is specified" do @client.sort(@key, :order => "ALPHA").should == ["1", "2"] end end context 'projections' do it 'projects element when :get is "#"' do @client.sort(@key, :get => '#').should == ['1', '2'] end it 'projects through a key pattern' do @client.sort(@key, :get => 'fake-redis-test:values_*').should == ['a', 'b'] end it 'projects through a key pattern and reflects element' do @client.sort(@key, :get => ['#', 'fake-redis-test:values_*']).should == [['1', 'a'], ['2', 'b']] end it 'projects through a hash key pattern' do @client.sort(@key, :get => 'fake-redis-test:hash_*->key').should == ['x', 'y'] end end context 'weights' do it 'weights by projecting through a key pattern' do @client.sort(@key, :by => "fake-redis-test:weight_*").should == ['2', '1'] end it 'weights by projecting through a key pattern and a specific order' do @client.sort(@key, :order => "DESC", :by => "fake-redis-test:weight_*").should == ['1', '2'] end end context 'limit' do it 'only returns requested window in the enumerable' do @client.sort(@key, :limit => [0, 1]).should == ['1'] end end context 'store' do it 'stores into another key' do @client.sort(@key, :store => "fake-redis-test:some_bucket").should == 2 @client.lrange("fake-redis-test:some_bucket", 0, -1).should == ['1', '2'] end it "stores into another key with other options specified" do @client.sort(@key, :store => "fake-redis-test:some_bucket", :by => "fake-redis-test:weight_*").should == 2 @client.lrange("fake-redis-test:some_bucket", 0, -1).should == ['2', '1'] end end end ruby-fakeredis-0.5.0/spec/lists_spec.rb0000644000175000017500000001435212616117431020214 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe "ListsMethods" do before(:each) do @client = Redis.new end it "should get an element from a list by its index" do @client.lpush("key1", "val1") @client.lpush("key1", "val2") @client.lindex("key1", 0).should be == "val2" @client.lindex("key1", -1).should be == "val1" @client.lindex("key1", 3).should be == nil end it "should insert an element before or after another element in a list" do @client.rpush("key1", "v1") @client.rpush("key1", "v3") @client.linsert("key1", :before, "v3", "v2") @client.lrange("key1", 0, -1).should be == ["v1", "v2", "v3"] end it 'should allow multiple values to be added to a list in a single rpush' do @client.rpush('key1', [1, 2, 3]) @client.lrange('key1', 0, -1).should be == ['1', '2', '3'] end it 'should allow multiple values to be added to a list in a single lpush' do @client.lpush('key1', [1, 2, 3]) @client.lrange('key1', 0, -1).should be == ['3', '2', '1'] end it "should error if an invalid where argument is given" do @client.rpush("key1", "v1") @client.rpush("key1", "v3") lambda { @client.linsert("key1", :invalid, "v3", "v2") }.should raise_error(Redis::CommandError, "ERR syntax error") end it "should get the length of a list" do @client.rpush("key1", "v1") @client.rpush("key1", "v2") @client.llen("key1").should be == 2 @client.llen("key2").should be == 0 end it "should remove and get the first element in a list" do @client.rpush("key1", "v1") @client.rpush("key1", "v2") @client.rpush("key1", "v3") @client.lpop("key1").should be == "v1" @client.lrange("key1", 0, -1).should be == ["v2", "v3"] end it "should prepend a value to a list" do @client.rpush("key1", "v1") @client.rpush("key1", "v2") @client.lrange("key1", 0, -1).should be == ["v1", "v2"] end it "should prepend a value to a list, only if the list exists" do @client.lpush("key1", "v1") @client.lpushx("key1", "v2") @client.lpushx("key2", "v3") @client.lrange("key1", 0, -1).should be == ["v2", "v1"] @client.llen("key2").should be == 0 end it "should get a range of elements from a list" do @client.rpush("key1", "v1") @client.rpush("key1", "v2") @client.rpush("key1", "v3") @client.lrange("key1", 1, -1).should be == ["v2", "v3"] end it "should remove elements from a list" do @client.rpush("key1", "v1") @client.rpush("key1", "v2") @client.rpush("key1", "v2") @client.rpush("key1", "v2") @client.rpush("key1", "v1") @client.lrem("key1", 1, "v1").should be == 1 @client.lrem("key1", -2, "v2").should be == 2 @client.llen("key1").should be == 2 end it "should remove list's key when list is empty" do @client.rpush("key1", "v1") @client.rpush("key1", "v2") @client.lrem("key1", 1, "v1") @client.lrem("key1", 1, "v2") @client.exists("key1").should be == false end it "should set the value of an element in a list by its index" do @client.rpush("key1", "one") @client.rpush("key1", "two") @client.rpush("key1", "three") @client.lset("key1", 0, "four") @client.lset("key1", -2, "five") @client.lrange("key1", 0, -1).should be == ["four", "five", "three"] lambda { @client.lset("key1", 4, "six") }.should raise_error(Redis::CommandError, "ERR index out of range") end it "should trim a list to the specified range" do @client.rpush("key1", "one") @client.rpush("key1", "two") @client.rpush("key1", "three") @client.ltrim("key1", 1, -1).should be == "OK" @client.lrange("key1", 0, -1).should be == ["two", "three"] end context "when the list is smaller than the requested trim" do before { @client.rpush("listOfOne", "one") } context "trimming with a negative start (specifying a max)" do before { @client.ltrim("listOfOne", -5, -1) } it "returns the unmodified list" do @client.lrange("listOfOne", 0, -1).should be == ["one"] end end end context "when the list is larger than the requested trim" do before do @client.rpush("maxTest", "one") @client.rpush("maxTest", "two") @client.rpush("maxTest", "three") @client.rpush("maxTest", "four") @client.rpush("maxTest", "five") @client.rpush("maxTest", "six") end context "trimming with a negative start (specifying a max)" do before { @client.ltrim("maxTest", -5, -1) } it "should trim a list to the specified maximum size" do @client.lrange("maxTest", 0, -1).should be == ["two","three", "four", "five", "six"] end end end it "should remove and return the last element in a list" do @client.rpush("key1", "one") @client.rpush("key1", "two") @client.rpush("key1", "three") @client.rpop("key1").should be == "three" @client.lrange("key1", 0, -1).should be == ["one", "two"] end it "should remove the last element in a list, append it to another list and return it" do @client.rpush("key1", "one") @client.rpush("key1", "two") @client.rpush("key1", "three") @client.rpoplpush("key1", "key2").should be == "three" @client.lrange("key1", 0, -1).should be == ["one", "two"] @client.lrange("key2", 0, -1).should be == ["three"] end context 'when the source list is empty' do it 'rpoplpush does not add anything to the destination list' do @client.rpoplpush("source", "destination") @client.lrange("destination", 0, -1).should be == [] end end it "should append a value to a list" do @client.rpush("key1", "one") @client.rpush("key1", "two") @client.lrange("key1", 0, -1).should be == ["one", "two"] end it "should append a value to a list, only if the list exists" do @client.rpush("key1", "one") @client.rpushx("key1", "two") @client.rpushx("key2", "two") @client.lrange("key1", 0, -1).should be == ["one", "two"] @client.lrange("key2", 0, -1).should be == [] end end end ruby-fakeredis-0.5.0/spec/spec_helper_live_redis.rb0000644000175000017500000000033112616117431022532 0ustar abhijithabhijithrequire "spec_helper" # Remove memory so we test against actual redis Redis::Connection.drivers.pop RSpec.configure do |config| config.before(:each) do Redis.new.flushall end end def fakeredis? false end ruby-fakeredis-0.5.0/spec/server_spec.rb0000644000175000017500000000503112616117431020356 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe "ServerMethods" do before(:each) do @client = Redis.new end it "should return the number of keys in the selected database" do @client.set("key1", "1") @client.set("key2", "2") @client.set("key2", "two") @client.dbsize.should be == 2 end it "should get information and statistics about the server" do @client.info.key?("redis_version").should be == true end it "should handle non-existent methods" do lambda { @client.idontexist }.should raise_error(Redis::CommandError, "ERR unknown command 'idontexist'") end describe "multiple databases" do it "should default to database 0" do @client.inspect.should =~ %r#/0>$# end it "should select another database" do @client.select(1) @client.inspect.should =~ %r#/1>$# end it "should store keys separately in each database" do @client.select(0).should be == "OK" @client.set("key1", "1") @client.set("key2", "2") @client.select(1) @client.set("key3", "3") @client.set("key4", "4") @client.set("key5", "5") @client.select(0) @client.dbsize.should be == 2 @client.exists("key1").should be true @client.exists("key3").should be false @client.select(1) @client.dbsize.should be == 3 @client.exists("key4").should be true @client.exists("key2").should be false @client.flushall @client.dbsize.should be == 0 @client.select(0) @client.dbsize.should be == 0 end it "should flush a database" do @client.select(0) @client.set("key1", "1") @client.set("key2", "2") @client.dbsize.should be == 2 @client.select(1) @client.set("key3", "3") @client.set("key4", "4") @client.dbsize.should be == 2 @client.flushdb.should be == "OK" @client.dbsize.should be == 0 @client.select(0) @client.dbsize.should be == 2 end it "should flush all databases" do @client.select(0) @client.set("key3", "3") @client.set("key4", "4") @client.dbsize.should be == 2 @client.select(1) @client.set("key3", "3") @client.set("key4", "4") @client.dbsize.should be == 2 @client.flushall.should be == "OK" @client.dbsize.should be == 0 @client.select(0) @client.dbsize.should be == 0 end end end end ruby-fakeredis-0.5.0/spec/memory_spec.rb0000644000175000017500000000113712616117431020363 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe 'time' do before(:each) do @client = Redis.new Time.stub_chain(:now, :to_f).and_return(1397845595.5139461) end it 'is an array' do expect(@client.time).to be_an_instance_of(Array) end it 'has two elements' do expect(@client.time.count).to eql 2 end if fakeredis? it 'has the current time in seconds' do expect(@client.time.first).to eql 1397845595 end it 'has the current leftover microseconds' do expect(@client.time.last).to eql 513946 end end end end ruby-fakeredis-0.5.0/spec/connection_spec.rb0000644000175000017500000000453712616117431021221 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe "ConnectionMethods" do before(:each) do @client = Redis.new end if fakeredis? it "should authenticate to the server" do @client.auth("pass").should be == "OK" end it "should re-use the same instance with the same host & port" do @client1 = Redis.new(:host => "localhost", :port => 1234) @client2 = Redis.new(:host => "localhost", :port => 1234) @client3 = Redis.new(:host => "localhost", :port => 5678) @client1.set("key1", "1") @client2.get("key1").should be == "1" @client3.get("key1").should be_nil @client2.set("key2", "2") @client1.get("key2").should be == "2" @client3.get("key2").should be_nil @client3.set("key3", "3") @client1.get("key3").should be_nil @client2.get("key3").should be_nil @client1.dbsize.should be == 2 @client2.dbsize.should be == 2 @client3.dbsize.should be == 1 end it "should connect to a specific database" do @client1 = Redis.new(:host => "localhost", :port => 1234, :db => 0) @client1.set("key1", "1") @client1.select(0) @client1.get("key1").should be == "1" @client2 = Redis.new(:host => "localhost", :port => 1234, :db => 1) @client2.set("key1", "1") @client2.select(1) @client2.get("key1").should == "1" end it "should not error with shutdown" do lambda { @client.shutdown }.should_not raise_error end it "should not error with quit" do lambda { @client.quit }.should_not raise_error end end it "should handle multiple clients using the same db instance" do @client1 = Redis.new(:host => "localhost", :port => 6379, :db => 1) @client2 = Redis.new(:host => "localhost", :port => 6379, :db => 2) @client1.set("key1", "one") @client1.get("key1").should be == "one" @client2.set("key2", "two") @client2.get("key2").should be == "two" @client1.get("key1").should be == "one" end it "should not error with a disconnected client" do @client1 = Redis.new @client1.client.disconnect @client1.get("key1").should be_nil end it "should echo the given string" do @client.echo("something").should == "something" end it "should ping the server" do @client.ping.should == "PONG" end end end ruby-fakeredis-0.5.0/spec/sort_method_spec.rb0000644000175000017500000000301712616117431021401 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe "#sort" do before(:each) do @client = Redis.new @client.set('fake-redis-test:values_1', 'a') @client.set('fake-redis-test:values_2', 'b') @client.set('fake-redis-test:weight_1', '2') @client.set('fake-redis-test:weight_2', '1') @client.hset('fake-redis-test:hash_1', 'key', 'x') @client.hset('fake-redis-test:hash_2', 'key', 'y') end context "WRONGTYPE Operation" do it "should not allow #sort on Strings" do @client.set("key1", "Hello") expect { @client.sort("key1") }.to raise_error(Redis::CommandError) end it "should not allow #sort on Hashes" do @client.hset("key1", "k1", "val1") @client.hset("key1", "k2", "val2") expect { @client.sort("key1") }.to raise_error(Redis::CommandError) end end context "list" do before do @key = "fake-redis-test:list_sort" @client.rpush(@key, '1') @client.rpush(@key, '2') end it_should_behave_like "a sortable" end context "set" do before do @key = "fake-redis-test:set_sort" @client.sadd(@key, '1') @client.sadd(@key, '2') end it_should_behave_like "a sortable" end context "zset" do before do @key = "fake-redis-test:zset_sort" @client.zadd(@key, 100, '1') @client.zadd(@key, 99, '2') end it_should_behave_like "a sortable" end end end ruby-fakeredis-0.5.0/spec/hashes_spec.rb0000644000175000017500000001520212616117431020324 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe "HashesMethods" do before(:each) do @client = Redis.new end it "should delete a hash field" do @client.hset("key1", "k1", "val1") @client.hset("key1", "k2", "val2") @client.hdel("key1", "k1").should be(1) @client.hget("key1", "k1").should be_nil @client.hget("key1", "k2").should be == "val2" end it "should remove a hash with no keys left" do @client.hset("key1", "k1", "val1") @client.hset("key1", "k2", "val2") @client.hdel("key1", "k1").should be(1) @client.hdel("key1", "k2").should be(1) @client.exists("key1").should be == false end it "should convert key to a string for hset" do m = double("key") m.stub(:to_s).and_return("foo") @client.hset("key1", m, "bar") @client.hget("key1", "foo").should be == "bar" end it "should convert key to a string for hget" do m = double("key") m.stub(:to_s).and_return("foo") @client.hset("key1", "foo", "bar") @client.hget("key1", m).should be == "bar" end it "should determine if a hash field exists" do @client.hset("key1", "index", "value") @client.hexists("key1", "index").should be true @client.hexists("key2", "i2").should be false end it "should get the value of a hash field" do @client.hset("key1", "index", "value") @client.hget("key1", "index").should be == "value" end it "should get all the fields and values in a hash" do @client.hset("key1", "i1", "val1") @client.hset("key1", "i2", "val2") @client.hgetall("key1").should be == {"i1" => "val1", "i2" => "val2"} end it "should increment the integer value of a hash field by the given number" do @client.hset("key1", "cont1", "5") @client.hincrby("key1", "cont1", "5").should be == 10 @client.hget("key1", "cont1").should be == "10" end it "should increment non existing hash keys" do @client.hget("key1", "cont2").should be_nil @client.hincrby("key1", "cont2", "5").should be == 5 end it "should increment the float value of a hash field by the given float" do @client.hset("key1", "cont1", 5.0) @client.hincrbyfloat("key1", "cont1", 4.1).should be == 9.1 @client.hget("key1", "cont1").should be == "9.1" end it "should increment non existing hash keys" do @client.hget("key1", "cont2").should be_nil @client.hincrbyfloat("key1", "cont2", 5.5).should be == 5.5 end it "should get all the fields in a hash" do @client.hset("key1", "i1", "val1") @client.hset("key1", "i2", "val2") @client.hkeys("key1").should =~ ["i1", "i2"] @client.hkeys("key2").should be == [] end it "should get the number of fields in a hash" do @client.hset("key1", "i1", "val1") @client.hset("key1", "i2", "val2") @client.hlen("key1").should be == 2 end it "should get the values of all the given hash fields" do @client.hset("key1", "i1", "val1") @client.hset("key1", "i2", "val2") @client.hmget("key1", "i1", "i2", "i3").should =~ ["val1", "val2", nil] @client.hmget("key1", ["i1", "i2", "i3"]).should =~ ["val1", "val2", nil] @client.hmget("key2", "i1", "i2").should be == [nil, nil] end it "should throw an argument error when you don't ask for any keys" do lambda { @client.hmget("key1") }.should raise_error(Redis::CommandError) end it "should reject an empty list of values" do lambda { @client.hmset("key") }.should raise_error(Redis::CommandError) @client.exists("key").should be false end it "rejects an insert with a key but no value" do lambda { @client.hmset("key", 'foo') }.should raise_error(Redis::CommandError) lambda { @client.hmset("key", 'foo', 3, 'bar') }.should raise_error(Redis::CommandError) @client.exists("key").should be false end it "should reject the wrong number of arguments" do lambda { @client.hmset("hash", "foo1", "bar1", "foo2", "bar2", "foo3") }.should raise_error(Redis::CommandError, "ERR wrong number of arguments for HMSET") end it "should set multiple hash fields to multiple values" do @client.hmset("key", "k1", "value1", "k2", "value2") @client.hget("key", "k1").should be == "value1" @client.hget("key", "k2").should be == "value2" end it "should set multiple hash fields from a ruby hash to multiple values" do @client.mapped_hmset("foo", :k1 => "value1", :k2 => "value2") @client.hget("foo", "k1").should be == "value1" @client.hget("foo", "k2").should be == "value2" end it "should set the string value of a hash field" do @client.hset("key1", "k1", "val1").should be == true @client.hset("key1", "k1", "val1").should be == false @client.hget("key1", "k1").should be == "val1" end it "should set the value of a hash field, only if the field does not exist" do @client.hset("key1", "k1", "val1") @client.hsetnx("key1", "k1", "value").should be == false @client.hsetnx("key1", "k2", "val2").should be == true @client.hsetnx("key1", :k1, "value").should be == false @client.hsetnx("key1", :k3, "val3").should be == true @client.hget("key1", "k1").should be == "val1" @client.hget("key1", "k2").should be == "val2" @client.hget("key1", "k3").should be == "val3" end it "should get all the values in a hash" do @client.hset("key1", "k1", "val1") @client.hset("key1", "k2", "val2") @client.hvals("key1").should =~ ["val1", "val2"] end it "should accept a list of array pairs as arguments and not throw an invalid argument number error" do @client.hmset("key1", [:k1, "val1"], [:k2, "val2"], [:k3, "val3"]) @client.hget("key1", :k1).should be == "val1" @client.hget("key1", :k2).should be == "val2" @client.hget("key1", :k3).should be == "val3" end it "should reject a list of arrays that contain an invalid number of arguments" do expect { @client.hmset("key1", [:k1, "val1"], [:k2, "val2", "bogus val"]) }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for HMSET") end it "should convert a integer field name to string for hdel" do @client.hset("key1", "1", 1) @client.hdel("key1", 1).should be(1) end it "should convert a integer field name to string for hexists" do @client.hset("key1", "1", 1) @client.hexists("key1", 1).should be true end it "should convert a integer field name to string for hincrby" do @client.hset("key1", 1, 0) @client.hincrby("key1", 1, 1).should be(1) end end end ruby-fakeredis-0.5.0/spec/compatibility_spec.rb0000644000175000017500000000031712616117431021723 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe "Compatibility" do it "should be accessible through FakeRedis::Redis" do lambda { FakeRedis::Redis.new }.should_not raise_error end end end ruby-fakeredis-0.5.0/spec/spec_helper.rb0000644000175000017500000000123412616117431020330 0ustar abhijithabhijith$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $LOAD_PATH.unshift(File.dirname(__FILE__)) require 'rspec' require 'fakeredis' require "fakeredis/rspec" require "support/shared_examples/sortable" RSpec.configure do |config| # replaces -b -fdoc --color in .rspec config.color = true config.default_formatter = "doc" config.backtrace_exclusion_patterns = [] config.mock_with :rspec do |c| # TODO: upgrade should syntax to expect syntax c.syntax = [:should, :expect] end config.expect_with :rspec do |c| # TODO: upgrade should syntax to expect syntax c.syntax = [:should, :expect] end end def fakeredis? true end ruby-fakeredis-0.5.0/spec/sorted_sets_spec.rb0000644000175000017500000004561112616117431021416 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis Infinity = 1.0/0.0 describe "SortedSetsMethods" do before(:each) do @client = Redis.new end it "should add a member to a sorted set, or update its score if it already exists" do @client.zadd("key", 1, "val").should be(true) @client.zscore("key", "val").should be == 1.0 @client.zadd("key", 2, "val").should be(false) @client.zscore("key", "val").should be == 2.0 # These assertions only work in redis-rb v3.0.2 or higher @client.zadd("key2", "inf", "val").should be == true @client.zscore("key2", "val").should be == Infinity @client.zadd("key3", "+inf", "val").should be == true @client.zscore("key3", "val").should be == Infinity @client.zadd("key4", "-inf", "val").should be == true @client.zscore("key4", "val").should be == -Infinity end it "should return a nil score for value not in a sorted set or empty key" do @client.zadd "key", 1, "val" @client.zscore("key", "val").should be == 1.0 @client.zscore("key", "val2").should be_nil @client.zscore("key2", "val").should be_nil end it "should add multiple members to a sorted set, or update its score if it already exists" do @client.zadd("key", [1, "val", 2, "val2"]).should be == 2 @client.zscore("key", "val").should be == 1 @client.zscore("key", "val2").should be == 2 @client.zadd("key", [[5, "val"], [3, "val3"], [4, "val4"]]).should be == 2 @client.zscore("key", "val").should be == 5 @client.zscore("key", "val2").should be == 2 @client.zscore("key", "val3").should be == 3 @client.zscore("key", "val4").should be == 4 @client.zadd("key", [[5, "val5"], [3, "val6"]]).should be == 2 @client.zscore("key", "val5").should be == 5 @client.zscore("key", "val6").should be == 3 end it "should error with wrong number of arguments when adding members" do lambda { @client.zadd("key") }.should raise_error(ArgumentError, "wrong number of arguments") lambda { @client.zadd("key", 1) }.should raise_error(ArgumentError, "wrong number of arguments") lambda { @client.zadd("key", [1]) }.should raise_error(Redis::CommandError, "ERR wrong number of arguments for 'zadd' command") lambda { @client.zadd("key", [1, "val", 2]) }.should raise_error(Redis::CommandError, "ERR syntax error") lambda { @client.zadd("key", [[1, "val"], [2]]) }.should raise_error(Redis::CommandError, "ERR syntax error") end it "should allow floats as scores when adding or updating" do @client.zadd("key", 4.321, "val").should be(true) @client.zscore("key", "val").should be == 4.321 @client.zadd("key", 54.3210, "val").should be(false) @client.zscore("key", "val").should be == 54.321 end it "should remove members from sorted sets" do @client.zrem("key", "val").should be(false) @client.zadd("key", 1, "val").should be(true) @client.zrem("key", "val").should be(true) end it "should remove multiple members from sorted sets" do @client.zrem("key2", %w(val)).should be == 0 @client.zrem("key2", %w(val val2 val3)).should be == 0 @client.zadd("key2", 1, "val") @client.zadd("key2", 1, "val2") @client.zadd("key2", 1, "val3") @client.zrem("key2", %w(val val2 val3 val4)).should be == 3 end it "should remove sorted set's key when it is empty" do @client.zadd("key", 1, "val") @client.zrem("key", "val") @client.exists("key").should be == false end it "should get the number of members in a sorted set" do @client.zadd("key", 1, "val2") @client.zadd("key", 2, "val1") @client.zadd("key", 5, "val3") @client.zcard("key").should be == 3 end it "should count the members in a sorted set with scores within the given values" do @client.zadd("key", 1, "val1") @client.zadd("key", 2, "val2") @client.zadd("key", 3, "val3") @client.zcount("key", 2, 3).should be == 2 end it "should increment the score of a member in a sorted set" do @client.zadd("key", 1, "val1") @client.zincrby("key", 2, "val1").should be == 3 @client.zscore("key", "val1").should be == 3 end it "initializes the sorted set if the key wasnt already set" do @client.zincrby("key", 1, "val1").should be == 1 end it "should convert the key to a string for zscore" do @client.zadd("key", 1, 1) @client.zscore("key", 1).should be == 1 end # These won't pass until redis-rb releases v3.0.2 it "should handle infinity values when incrementing a sorted set key" do @client.zincrby("bar", "+inf", "s2").should be == Infinity @client.zincrby("bar", "-inf", "s1").should be == -Infinity end it "should return a range of members in a sorted set, by index" do @client.zadd("key", 1, "one") @client.zadd("key", 2, "two") @client.zadd("key", 3, "three") @client.zrange("key", 0, -1).should be == ["one", "two", "three"] @client.zrange("key", 1, 2).should be == ["two", "three"] @client.zrange("key", 0, -1, :withscores => true).should be == [["one", 1], ["two", 2], ["three", 3]] @client.zrange("key", 1, 2, :with_scores => true).should be == [["two", 2], ["three", 3]] end it "should sort zrange results logically" do @client.zadd("key", 5, "val2") @client.zadd("key", 5, "val3") @client.zadd("key", 5, "val1") @client.zrange("key", 0, -1).should be == %w(val1 val2 val3) @client.zrange("key", 0, -1, :with_scores => true).should be == [["val1", 5], ["val2", 5], ["val3", 5]] end it "should return a reversed range of members in a sorted set, by index" do @client.zadd("key", 1, "one") @client.zadd("key", 2, "two") @client.zadd("key", 3, "three") @client.zrevrange("key", 0, -1).should be == ["three", "two", "one"] @client.zrevrange("key", 1, 2).should be == ["two", "one"] @client.zrevrange("key", 0, -1, :withscores => true).should be == [["three", 3], ["two", 2], ["one", 1]] @client.zrevrange("key", 0, -1, :with_scores => true).should be == [["three", 3], ["two", 2], ["one", 1]] end it "should return a range of members in a sorted set, by score" do @client.zadd("key", 1, "one") @client.zadd("key", 2, "two") @client.zadd("key", 3, "three") @client.zrangebyscore("key", 0, 100).should be == ["one", "two", "three"] @client.zrangebyscore("key", 1, 2).should be == ["one", "two"] @client.zrangebyscore("key", 1, '(2').should be == ['one'] @client.zrangebyscore("key", '(1', 2).should be == ['two'] @client.zrangebyscore("key", '(1', '(2').should be == [] @client.zrangebyscore("key", 0, 100, :withscores => true).should be == [["one", 1], ["two", 2], ["three", 3]] @client.zrangebyscore("key", 1, 2, :with_scores => true).should be == [["one", 1], ["two", 2]] @client.zrangebyscore("key", 0, 100, :limit => [0, 1]).should be == ["one"] @client.zrangebyscore("key", 0, 100, :limit => [0, -1]).should be == ["one", "two", "three"] @client.zrangebyscore("key", 0, 100, :limit => [1, -1], :with_scores => true).should be == [["two", 2], ["three", 3]] @client.zrangebyscore("key", '-inf', '+inf').should be == ["one", "two", "three"] @client.zrangebyscore("key", 2, '+inf').should be == ["two", "three"] @client.zrangebyscore("key", '-inf', 2).should be == ['one', "two"] @client.zrangebyscore("badkey", 1, 2).should be == [] end it "should return a reversed range of members in a sorted set, by score" do @client.zadd("key", 1, "one") @client.zadd("key", 2, "two") @client.zadd("key", 3, "three") @client.zrevrangebyscore("key", 100, 0).should be == ["three", "two", "one"] @client.zrevrangebyscore("key", 2, 1).should be == ["two", "one"] @client.zrevrangebyscore("key", 1, 2).should be == [] @client.zrevrangebyscore("key", 2, 1, :with_scores => true).should be == [["two", 2.0], ["one", 1.0]] @client.zrevrangebyscore("key", 100, 0, :limit => [0, 1]).should be == ["three"] @client.zrevrangebyscore("key", 100, 0, :limit => [0, -1]).should be == ["three", "two", "one"] @client.zrevrangebyscore("key", 100, 0, :limit => [1, -1], :with_scores => true).should be == [["two", 2.0], ["one", 1.0]] end it "should determine the index of a member in a sorted set" do @client.zadd("key", 1, "one") @client.zadd("key", 2, "two") @client.zadd("key", 3, "three") @client.zrank("key", "three").should be == 2 @client.zrank("key", "four").should be_nil end it "should determine the reversed index of a member in a sorted set" do @client.zadd("key", 1, "one") @client.zadd("key", 2, "two") @client.zadd("key", 3, "three") @client.zrevrank("key", "three").should be == 0 @client.zrevrank("key", "four").should be_nil end it "should not raise errors for zrank() on accessing a non-existing key in a sorted set" do @client.zrank("no_such_key", "no_suck_id").should be_nil end it "should not raise errors for zrevrank() on accessing a non-existing key in a sorted set" do @client.zrevrank("no_such_key", "no_suck_id").should be_nil end describe "#zinterstore" do before do @client.zadd("key1", 1, "one") @client.zadd("key1", 2, "two") @client.zadd("key1", 3, "three") @client.zadd("key2", 5, "two") @client.zadd("key2", 7, "three") @client.sadd("key3", 'one') @client.sadd("key3", 'two') end it "should intersect two keys with custom scores" do @client.zinterstore("out", ["key1", "key2"]).should be == 2 @client.zrange("out", 0, -1, :with_scores => true).should be == [['two', (2 + 5)], ['three', (3 + 7)]] end it "should intersect two keys with a default score" do @client.zinterstore("out", ["key1", "key3"]).should be == 2 @client.zrange("out", 0, -1, :with_scores => true).should be == [['one', (1 + 1)], ['two', (2 + 1)]] end it "should intersect more than two keys" do @client.zinterstore("out", ["key1", "key2", "key3"]).should be == 1 @client.zrange("out", 0, -1, :with_scores => true).should be == [['two', (2 + 5 + 1)]] end it "should not intersect an unknown key" do @client.zinterstore("out", ["key1", "no_key"]).should be == 0 @client.zrange("out", 0, -1, :with_scores => true).should be == [] end it "should intersect two keys by minimum values" do @client.zinterstore("out", ["key1", "key2"], :aggregate => :min).should be == 2 @client.zrange("out", 0, -1, :with_scores => true).should be == [["two", 2], ["three", 3]] end it "should intersect two keys by maximum values" do @client.zinterstore("out", ["key1", "key2"], :aggregate => :max).should be == 2 @client.zrange("out", 0, -1, :with_scores => true).should be == [["two", 5], ["three", 7]] end it "should intersect two keys by explicitly summing values" do @client.zinterstore("out", %w(key1 key2), :aggregate => :sum).should be == 2 @client.zrange("out", 0, -1, :with_scores => true).should be == [["two", (2 + 5)], ["three", (3 + 7)]] end it "should intersect two keys with weighted values" do @client.zinterstore("out", %w(key1 key2), :weights => [10, 1]).should be == 2 @client.zrange("out", 0, -1, :with_scores => true).should be == [["two", (2 * 10 + 5)], ["three", (3 * 10 + 7)]] end it "should intersect two keys with weighted minimum values" do @client.zinterstore("out", %w(key1 key2), :weights => [10, 1], :aggregate => :min).should be == 2 @client.zrange("out", 0, -1, :with_scores => true).should be == [["two", 5], ["three", 7]] end it "should intersect two keys with weighted maximum values" do @client.zinterstore("out", %w(key1 key2), :weights => [10, 1], :aggregate => :max).should be == 2 @client.zrange("out", 0, -1, :with_scores => true).should be == [["two", (2 * 10)], ["three", (3 * 10)]] end it "should error without enough weights given" do lambda { @client.zinterstore("out", %w(key1 key2), :weights => []) }.should raise_error(Redis::CommandError, "ERR syntax error") lambda { @client.zinterstore("out", %w(key1 key2), :weights => [10]) }.should raise_error(Redis::CommandError, "ERR syntax error") end it "should error with too many weights given" do lambda { @client.zinterstore("out", %w(key1 key2), :weights => [10, 1, 1]) }.should raise_error(Redis::CommandError, "ERR syntax error") end it "should error with an invalid aggregate" do lambda { @client.zinterstore("out", %w(key1 key2), :aggregate => :invalid) }.should raise_error(Redis::CommandError, "ERR syntax error") end end context "zremrangebyscore" do it "should remove items by score" do @client.zadd("key", 1, "one") @client.zadd("key", 2, "two") @client.zadd("key", 3, "three") @client.zremrangebyscore("key", 0, 2).should be == 2 @client.zcard("key").should be == 1 end it "should remove items by score with infinity" do # Issue #50 @client.zadd("key", 10.0, "one") @client.zadd("key", 20.0, "two") @client.zadd("key", 30.0, "three") @client.zremrangebyscore("key", "-inf", "+inf").should be == 3 @client.zcard("key").should be == 0 @client.zscore("key", "one").should be_nil @client.zscore("key", "two").should be_nil @client.zscore("key", "three").should be_nil end it "should return 0 if the key didn't exist" do @client.zremrangebyscore("key", 0, 2).should be == 0 end end context '#zremrangebyrank' do it 'removes all elements with in the given range' do @client.zadd("key", 1, "one") @client.zadd("key", 2, "two") @client.zadd("key", 3, "three") @client.zremrangebyrank("key", 0, 1).should be == 2 @client.zcard('key').should be == 1 end it 'handles out of range requests' do @client.zadd("key", 1, "one") @client.zadd("key", 2, "two") @client.zadd("key", 3, "three") @client.zremrangebyrank("key", 25, -1).should be == 0 @client.zcard('key').should be == 3 end it "should return 0 if the key didn't exist" do @client.zremrangebyrank("key", 0, 1).should be == 0 end end describe "#zunionstore" do before do @client.zadd("key1", 1, "val1") @client.zadd("key1", 2, "val2") @client.zadd("key1", 3, "val3") @client.zadd("key2", 5, "val2") @client.zadd("key2", 7, "val3") @client.sadd("key3", "val1") @client.sadd("key3", "val2") end it "should union two keys with custom scores" do @client.zunionstore("out", %w(key1 key2)).should be == 3 @client.zrange("out", 0, -1, :with_scores => true).should be == [["val1", 1], ["val2", (2 + 5)], ["val3", (3 + 7)]] end it "should union two keys with a default score" do @client.zunionstore("out", %w(key1 key3)).should be == 3 @client.zrange("out", 0, -1, :with_scores => true).should be == [["val1", (1 + 1)], ["val2", (2 + 1)], ["val3", 3]] end it "should union more than two keys" do @client.zunionstore("out", %w(key1 key2 key3)).should be == 3 @client.zrange("out", 0, -1, :with_scores => true).should be == [["val1", (1 + 1)], ["val2", (2 + 5 + 1)], ["val3", (3 + 7)]] end it "should union with an unknown key" do @client.zunionstore("out", %w(key1 no_key)).should be == 3 @client.zrange("out", 0, -1, :with_scores => true).should be == [["val1", 1], ["val2", 2], ["val3", 3]] end it "should union two keys by minimum values" do @client.zunionstore("out", %w(key1 key2), :aggregate => :min).should be == 3 @client.zrange("out", 0, -1, :with_scores => true).should be == [["val1", 1], ["val2", 2], ["val3", 3]] end it "should union two keys by maximum values" do @client.zunionstore("out", %w(key1 key2), :aggregate => :max).should be == 3 @client.zrange("out", 0, -1, :with_scores => true).should be == [["val1", 1], ["val2", 5], ["val3", 7]] end it "should union two keys by explicitly summing values" do @client.zunionstore("out", %w(key1 key2), :aggregate => :sum).should be == 3 @client.zrange("out", 0, -1, :with_scores => true).should be == [["val1", 1], ["val2", (2 + 5)], ["val3", (3 + 7)]] end it "should union two keys with weighted values" do @client.zunionstore("out", %w(key1 key2), :weights => [10, 1]).should be == 3 @client.zrange("out", 0, -1, :with_scores => true).should be == [["val1", (1 * 10)], ["val2", (2 * 10 + 5)], ["val3", (3 * 10 + 7)]] end it "should union two keys with weighted minimum values" do @client.zunionstore("out", %w(key1 key2), :weights => [10, 1], :aggregate => :min).should be == 3 @client.zrange("out", 0, -1, :with_scores => true).should be == [["val2", 5], ["val3", 7], ["val1", (1 * 10)]] end it "should union two keys with weighted maximum values" do @client.zunionstore("out", %w(key1 key2), :weights => [10, 1], :aggregate => :max).should be == 3 @client.zrange("out", 0, -1, :with_scores => true).should be == [["val1", (1 * 10)], ["val2", (2 * 10)], ["val3", (3 * 10)]] end it "should error without enough weights given" do lambda { @client.zunionstore("out", %w(key1 key2), :weights => []) }.should raise_error(Redis::CommandError, "ERR syntax error") lambda { @client.zunionstore("out", %w(key1 key2), :weights => [10]) }.should raise_error(Redis::CommandError, "ERR syntax error") end it "should error with too many weights given" do lambda { @client.zunionstore("out", %w(key1 key2), :weights => [10, 1, 1]) }.should raise_error(Redis::CommandError, "ERR syntax error") end it "should error with an invalid aggregate" do lambda { @client.zunionstore("out", %w(key1 key2), :aggregate => :invalid) }.should raise_error(Redis::CommandError, "ERR syntax error") end end #it "should remove all members in a sorted set within the given indexes" #it "should return a range of members in a sorted set, by index, with scores ordered from high to low" #it "should return a range of members in a sorted set, by score, with scores ordered from high to low" #it "should determine the index of a member in a sorted set, with scores ordered from high to low" #it "should get the score associated with the given member in a sorted set" #it "should add multiple sorted sets and store the resulting sorted set in a new key" it "zrem should remove members add by zadd" do @client.zadd("key1", 1, 3) @client.zrem("key1", 3) @client.zscore("key1", 3).should be_nil end end end ruby-fakeredis-0.5.0/spec/upcase_method_name_spec.rb0000644000175000017500000000054412616117431022674 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe "UPCASE method name will call downcase method" do before do @client = Redis.new end it "#ZCOUNT" do @client.ZCOUNT("key", 2, 3).should == @client.zcount("key", 2, 3) end it "#ZSCORE" do @client.ZSCORE("key", 2).should == @client.zscore("key", 2) end end end ruby-fakeredis-0.5.0/spec/transactions_spec.rb0000644000175000017500000000423712616117431021567 0ustar abhijithabhijithrequire 'spec_helper' module FakeRedis describe "TransactionsMethods" do before(:all) do @client = Redis.new end before(:each) do @client.discard rescue nil end context '#multi' do it "should respond with 'OK'" do @client.multi.should == 'OK' end it "should forbid nesting" do @client.multi lambda{@client.multi}.should raise_error(Redis::CommandError) end it "should mark the start of a transaction block" do transaction = @client.multi do |multi| multi.set("key1", "1") multi.set("key2", "2") multi.expire("key1", 123) multi.mget("key1", "key2") end transaction.should be == ["OK", "OK", true, ["1", "2"]] end end context '#discard' do it "should responde with 'OK' after #multi" do @client.multi @client.discard.should == 'OK' end it "can't be run outside of #multi/#exec" do lambda{@client.discard}.should raise_error(Redis::CommandError) end end context '#exec' do it "can't be run outside of #multi" do lambda{@client.exec}.should raise_error(Redis::CommandError) end end context 'saving up commands for later' do before(:each) do @client.multi @string = 'fake-redis-test:string' @list = 'fake-redis-test:list' end it "makes commands respond with 'QUEUED'" do @client.set(@string, 'string').should == 'QUEUED' @client.lpush(@list, 'list').should == 'QUEUED' end it "gives you the commands' responses when you call #exec" do @client.set(@string, 'string') @client.lpush(@list, 'list') @client.lpush(@list, 'list') @client.exec.should == ['OK', 1, 2] end it "does not raise exceptions, but rather puts them in #exec's response" do @client.set(@string, 'string') @client.lpush(@string, 'oops!') @client.lpush(@list, 'list') responses = @client.exec responses[0].should == 'OK' responses[1].should be_a(RuntimeError) responses[2].should == 1 end end end end ruby-fakeredis-0.5.0/README.md0000644000175000017500000000455112616117431016044 0ustar abhijithabhijith# FakeRedis [![Build Status](https://secure.travis-ci.org/guilleiguaran/fakeredis.png)](http://travis-ci.org/guilleiguaran/fakeredis) This a fake implementation of redis-rb for machines without Redis or test environments ## Installation Install the gem: gem install fakeredis Add it to your Gemfile: gem "fakeredis" ## Versions FakeRedis currently supports redis-rb v3.x.y or later, if you are using redis-rb v2.2.x install the version 0.3.x: gem install fakeredis -v "~> 0.3.0" or use the branch 0-3-x on your Gemfile: gem "fakeredis", :git => "git://github.com/guilleiguaran/fakeredis.git", :branch => "0-3-x" ## Usage You can use FakeRedis without any changes: require "fakeredis" redis = Redis.new >> redis.set "foo", "bar" => "OK" >> redis.get "foo" => "bar" Read [redis-rb](https://github.com/ezmobius/redis-rb) documentation and [Redis](http://redis.io) homepage for more info about commands ## Usage with RSpec Require this either in your Gemfile or in RSpec's support scripts. So either: # Gemfile group :test do gem "rspec" gem "fakeredis", :require => "fakeredis/rspec" end Or: # spec/support/fakeredis.rb require 'fakeredis/rspec' ## Acknowledgements * [dim](https://github.com/dim) * [czarneckid](https://github.com/czarneckid) * [obrie](https://github.com/obrie) * [jredville](https://github.com/jredville) * [redsquirrel](https://github.com/redsquirrel) * [dpick](https://github.com/dpick) * [caius](https://github.com/caius) * [Travis-CI](http://travis-ci.org/) (Travis-CI also uses Fakeredis in its tests!!!) ## Contributing to FakeRedis * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it * Fork the project * Start a feature/bugfix branch * Commit and push until you are happy with your contribution * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally. * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it. ## Copyright Copyright (c) 2011-2014 Guillermo Iguaran. See LICENSE for further details.