1# frozen_string_literal: true
2
3require "simplecov"
4SimpleCov.start do
5 add_filter "/test/"
6 enable_coverage :branch
7end
8
9require "minitest/autorun"
10require "webmock/minitest"
11
12begin
13 require "pry-rescue/minitest"
14 require "pry-reload"
15 require "pry-byebug"
16
17 module Minitest
18 class Test
19 alias old_capture_exceptions capture_exceptions
20 def capture_exceptions
21 old_capture_exceptions do
22 yield
23 rescue Minitest::Skip => e
24 failures << e
25 end
26 end
27 end
28 end
29rescue LoadError, NameError
30 # Just helpers for dev, no big deal if missing
31 nil
32end
33
34$VERBOSE = nil
35ARGV[0] = "component"
36
37class FakeRedis
38 def initialize(values={})
39 @values = values
40 end
41
42 def reset!(values={})
43 @values = values
44 end
45
46 def set(key, value, *)
47 @values[key] = value
48 EMPromise.resolve("OK")
49 end
50
51 def setex(key, _expiry, value)
52 set(key, value)
53 end
54
55 def del(*keys)
56 keys.each { |key| @values.delete(key) }
57 end
58
59 def mget(*keys)
60 EMPromise.all(keys.map(&method(:get)))
61 end
62
63 def get(key)
64 EMPromise.resolve(@values[key])
65 end
66
67 def getbit(key, bit)
68 get(key).then { |v| v.to_i.to_s(2)[bit].to_i }
69 end
70
71 def bitfield(key, *ops)
72 get(key).then do |v|
73 bits = v.to_i.to_s(2)
74 ops.each_slice(3).map do |(op, encoding, offset)|
75 raise "unsupported bitfield op" unless op == "GET"
76 raise "unsupported bitfield op" unless encoding == "u1"
77
78 bits[offset].to_i
79 end
80 end
81 end
82
83 def hget(key, field)
84 @values.dig(key, field)
85 end
86
87 def hincrby(key, field, incrby)
88 @values[key] ||= {}
89 @values[key][field] ||= 0
90 @values[key][field] += incrby
91 end
92
93 def sadd(key, member)
94 @values[key] ||= Set.new
95 @values[key] << member
96 end
97
98 def srem(key, member)
99 @values[key].delete(member)
100 end
101
102 def scard(key)
103 @values[key]&.size || 0
104 end
105
106 def expire(_, _); end
107
108 def exists(*keys)
109 EMPromise.resolve(
110 @values.select { |k, _| keys.include? k }.size.to_s
111 )
112 end
113
114 def lindex(key, index)
115 get(key).then { |v| v&.fetch(index) }
116 end
117
118 def lrange(key, sindex, eindex)
119 get(key).then { |v| v ? v[sindex..eindex] : [] }
120 end
121
122 def rpush(key, *values)
123 @values[key] ||= []
124 values.each { |v| @values[key].push(v) }
125 end
126
127 def multi
128 end
129
130 def exec
131 end
132
133 def discard
134 end
135
136 def xadd(stream, id, *args)
137 @values[stream] ||= []
138 entry_id = id == "*" ? "#{Time.now.to_i}-0" : id
139 fields = Hash[*args]
140 @values[stream] << { id: entry_id, fields: fields }
141 EMPromise.resolve(entry_id)
142 end
143
144 def stream_entries(stream)
145 EMPromise.resolve(@values[stream] || [])
146 end
147end
148
149REDIS = FakeRedis.new
150
151module Minitest
152 class Test
153 def with_stubs(stubs, &block)
154 if stubs.empty?
155 block.call
156 else
157 obj, method, value = stubs.first
158 obj.stub(method, value) do
159 with_stubs(stubs[1..], &block)
160 end
161 end
162 end
163
164 def self.em(m)
165 alias_method "raw_#{m}", m
166 define_method(m) do
167 $panic = nil
168 e = nil
169 EM.run do
170 Fiber.new {
171 begin
172 send("raw_#{m}")
173 rescue
174 e = $!
175 ensure
176 EM.stop
177 end
178 }.resume
179 end
180 raise e if e
181 end
182 end
183 end
184end