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