redstruct 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +15 -11
- data/Rakefile +5 -5
- data/lib/redstruct/all.rb +14 -0
- data/lib/redstruct/configuration.rb +9 -6
- data/lib/redstruct/connection_proxy.rb +123 -0
- data/lib/redstruct/counter.rb +96 -0
- data/lib/redstruct/error.rb +2 -0
- data/lib/redstruct/factory/object.rb +31 -0
- data/lib/redstruct/factory.rb +94 -55
- data/lib/redstruct/hash.rb +123 -0
- data/lib/redstruct/list.rb +315 -0
- data/lib/redstruct/lock.rb +183 -0
- data/lib/redstruct/script.rb +104 -0
- data/lib/redstruct/set.rb +155 -0
- data/lib/redstruct/sorted_set/slice.rb +124 -0
- data/lib/redstruct/sorted_set.rb +153 -0
- data/lib/redstruct/string.rb +66 -0
- data/lib/redstruct/struct.rb +87 -0
- data/lib/redstruct/utils/coercion.rb +14 -8
- data/lib/redstruct/utils/inspectable.rb +8 -4
- data/lib/redstruct/utils/iterable.rb +52 -0
- data/lib/redstruct/utils/scriptable.rb +32 -6
- data/lib/redstruct/version.rb +4 -1
- data/lib/redstruct.rb +17 -51
- data/lib/yard/defscript_handler.rb +5 -3
- data/test/redstruct/configuration_test.rb +13 -0
- data/test/redstruct/connection_proxy_test.rb +85 -0
- data/test/redstruct/counter_test.rb +108 -0
- data/test/redstruct/factory/object_test.rb +21 -0
- data/test/redstruct/factory_test.rb +136 -0
- data/test/redstruct/hash_test.rb +138 -0
- data/test/redstruct/list_test.rb +244 -0
- data/test/redstruct/lock_test.rb +108 -0
- data/test/redstruct/script_test.rb +53 -0
- data/test/redstruct/set_test.rb +219 -0
- data/test/redstruct/sorted_set/slice_test.rb +10 -0
- data/test/redstruct/sorted_set_test.rb +219 -0
- data/test/redstruct/string_test.rb +8 -0
- data/test/redstruct/struct_test.rb +61 -0
- data/test/redstruct/utils/coercion_test.rb +33 -0
- data/test/redstruct/utils/inspectable_test.rb +31 -0
- data/test/redstruct/utils/iterable_test.rb +94 -0
- data/test/redstruct/utils/scriptable_test.rb +67 -0
- data/test/redstruct_test.rb +14 -0
- data/test/test_helper.rb +77 -1
- metadata +58 -26
- data/lib/redstruct/connection.rb +0 -47
- data/lib/redstruct/factory/creation.rb +0 -95
- data/lib/redstruct/factory/deserialization.rb +0 -7
- data/lib/redstruct/hls/lock.rb +0 -175
- data/lib/redstruct/hls/queue.rb +0 -29
- data/lib/redstruct/hls.rb +0 -2
- data/lib/redstruct/types/base.rb +0 -36
- data/lib/redstruct/types/counter.rb +0 -65
- data/lib/redstruct/types/hash.rb +0 -72
- data/lib/redstruct/types/list.rb +0 -76
- data/lib/redstruct/types/script.rb +0 -56
- data/lib/redstruct/types/set.rb +0 -96
- data/lib/redstruct/types/sorted_set.rb +0 -129
- data/lib/redstruct/types/string.rb +0 -64
- data/lib/redstruct/types/struct.rb +0 -58
- data/lib/releaser/logger.rb +0 -15
- data/lib/releaser/repository.rb +0 -32
- data/lib/tasks/release.rake +0 -49
- data/test/redstruct/restruct_test.rb +0 -4
@@ -0,0 +1,219 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module Redstruct
|
6
|
+
class SetTest < Redstruct::Test
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
@factory = create_factory
|
10
|
+
@set = @factory.set('set')
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_clear
|
14
|
+
@set << 'item'
|
15
|
+
refute @set.empty?, 'ensure it is not empty before clearing'
|
16
|
+
|
17
|
+
@set.clear
|
18
|
+
assert @set.empty?, 'should be empty after clearing'
|
19
|
+
end
|
20
|
+
|
21
|
+
# assumes srandmember works correctly about the randomization part
|
22
|
+
def test_random
|
23
|
+
ensure_command_called(@set, :srandmember, 1).twice
|
24
|
+
assert_nil @set.random, 'should return nothing when the set is empty'
|
25
|
+
|
26
|
+
@set << 'a'
|
27
|
+
assert_equal 'a', @set.random, 'should return a, as it is the only member anyway'
|
28
|
+
|
29
|
+
amount = rand(10) + 2
|
30
|
+
requested = amount / 2
|
31
|
+
@set.add(*(1..amount).map { |i| i })
|
32
|
+
|
33
|
+
ensure_command_called(@set, :srandmember, requested).once
|
34
|
+
assert_equal requested, @set.random(count: requested).size, 'should return the amount of items requested'
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_empty?
|
38
|
+
assert @set.empty?, 'should be initially empty'
|
39
|
+
@set << 'a'
|
40
|
+
refute @set.empty?, 'should not be empty once it has one element'
|
41
|
+
@set.clear
|
42
|
+
assert @set.empty?, 'should be empty after clearing'
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_contain?
|
46
|
+
refute @set.contain?('a'), 'should not contain anything'
|
47
|
+
@set << 'a'
|
48
|
+
assert @set.contain?('a'), 'should now contain a'
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_add
|
52
|
+
assert @set.empty?, 'set should be empty before any addition'
|
53
|
+
assert_equal 2, @set.add(1, 2), 'should return the number of added elements'
|
54
|
+
assert_equal 1, @set.add(1, 2, 3), 'should return only the number of added elements'
|
55
|
+
assert_equal ::Set.new(%w[1 2 3]), @set.to_set, 'should return a set containing 1, 2, 3'
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_pop
|
59
|
+
values = %w[1 2 3]
|
60
|
+
assert @set.empty?, 'should start empty'
|
61
|
+
|
62
|
+
@set.add(*values)
|
63
|
+
popped = @set.pop
|
64
|
+
assert values.include?(popped), 'should have popped one of the added values'
|
65
|
+
|
66
|
+
expected = values - [popped]
|
67
|
+
assert_equal ::Set.new(expected), @set.to_set, 'should return a set containing the remaining elements'
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_remove
|
71
|
+
values = %w[1 2 3]
|
72
|
+
assert @set.empty?, 'should start empty'
|
73
|
+
|
74
|
+
@set.add(*values)
|
75
|
+
assert @set.remove('1'), 'should remove the element correctly'
|
76
|
+
assert_equal ::Set.new(%w[2 3]), @set.to_set, 'should return the remaining elements'
|
77
|
+
|
78
|
+
assert_equal 2, @set.remove(2, 3, 4), 'should remove 2 elements only'
|
79
|
+
assert @set.empty?, 'should be empty once we remove everything'
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_size
|
83
|
+
values = %w[1 2 3]
|
84
|
+
assert_equal 0, @set.size, 'should have no elements initially'
|
85
|
+
|
86
|
+
@set.add(*values)
|
87
|
+
assert_equal values.size, @set.size, 'should return the correct number of elements'
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_difference
|
91
|
+
set_contents = %w[1 2 3 4]
|
92
|
+
set2_contents = %w[3 4 5 6]
|
93
|
+
|
94
|
+
set2 = @factory.set('set2')
|
95
|
+
|
96
|
+
@set.add(*set_contents)
|
97
|
+
set2.add(*set2_contents)
|
98
|
+
|
99
|
+
assert_equal ::Set.new(%w[1 2]), @set - set2, 'should return elements not contained in set2'
|
100
|
+
assert_equal ::Set.new(%w[5 6]), set2 - @set, 'should return elements not contained in set'
|
101
|
+
|
102
|
+
assert_equal ::Set.new(set_contents), @set.to_set, 'should still be the same'
|
103
|
+
assert_equal ::Set.new(set2_contents), set2.to_set, 'should still be the same'
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_difference_dest
|
107
|
+
set_contents = %w[1 2 3 4]
|
108
|
+
set2_contents = %w[3 4 5 6]
|
109
|
+
|
110
|
+
set2 = @factory.set('set2')
|
111
|
+
set3 = @factory.set('set3')
|
112
|
+
|
113
|
+
@set.add(*set_contents)
|
114
|
+
set2.add(*set2_contents)
|
115
|
+
|
116
|
+
assert_equal 2, @set.difference(set2, dest: set3), 'should have 2 elements stored in the new set'
|
117
|
+
assert_equal ::Set.new(%w[1 2]), set3.to_set, 'should return elements not contained in set2'
|
118
|
+
|
119
|
+
assert_equal ::Set.new(set_contents), @set.to_set, 'should still be the same'
|
120
|
+
assert_equal ::Set.new(set2_contents), set2.to_set, 'should still be the same'
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_intersection
|
124
|
+
set_contents = %w[1 2 3 4]
|
125
|
+
set2_contents = %w[3 4 5 6]
|
126
|
+
|
127
|
+
set2 = @factory.set('set2')
|
128
|
+
|
129
|
+
@set.add(*set_contents)
|
130
|
+
set2.add(*set2_contents)
|
131
|
+
|
132
|
+
assert_equal ::Set.new(%w[3 4]), @set | set2, 'should return elements contained in both sets'
|
133
|
+
assert_equal ::Set.new(%w[3 4]), set2 | @set, 'should return elements contained in both sets'
|
134
|
+
|
135
|
+
assert_equal ::Set.new(set_contents), @set.to_set, 'should still be the same'
|
136
|
+
assert_equal ::Set.new(set2_contents), set2.to_set, 'should still be the same'
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_intersection_dest
|
140
|
+
set_contents = %w[1 2 3 4]
|
141
|
+
set2_contents = %w[3 4 5 6]
|
142
|
+
|
143
|
+
set2 = @factory.set('set2')
|
144
|
+
set3 = @factory.set('set3')
|
145
|
+
|
146
|
+
@set.add(*set_contents)
|
147
|
+
set2.add(*set2_contents)
|
148
|
+
|
149
|
+
assert_equal 2, @set.intersection(set2, dest: set3), 'should have 2 elements stored in the new set'
|
150
|
+
assert_equal ::Set.new(%w[3 4]), set3.to_set, 'should return elements contained in both sets'
|
151
|
+
|
152
|
+
assert_equal ::Set.new(set_contents), @set.to_set, 'should still be the same'
|
153
|
+
assert_equal ::Set.new(set2_contents), set2.to_set, 'should still be the same'
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_union
|
157
|
+
set_contents = %w[1 2 3 4]
|
158
|
+
set2_contents = %w[3 4 5 6]
|
159
|
+
|
160
|
+
set2 = @factory.set('set2')
|
161
|
+
|
162
|
+
@set.add(*set_contents)
|
163
|
+
set2.add(*set2_contents)
|
164
|
+
|
165
|
+
assert_equal ::Set.new(%w[1 2 3 4 5 6]), @set + set2, 'should return elements contained in either sets'
|
166
|
+
assert_equal ::Set.new(%w[1 2 3 4 5 6]), set2 + @set, 'should return elements contained in either sets'
|
167
|
+
|
168
|
+
assert_equal ::Set.new(set_contents), @set.to_set, 'should still be the same'
|
169
|
+
assert_equal ::Set.new(set2_contents), set2.to_set, 'should still be the same'
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_union_dest
|
173
|
+
set_contents = %w[1 2 3 4]
|
174
|
+
set2_contents = %w[3 4 5 6]
|
175
|
+
|
176
|
+
set2 = @factory.set('set2')
|
177
|
+
set3 = @factory.set('set3')
|
178
|
+
|
179
|
+
@set.add(*set_contents)
|
180
|
+
set2.add(*set2_contents)
|
181
|
+
|
182
|
+
assert_equal 6, @set.union(set2, dest: set3), 'should have 6 elements stored in the new set'
|
183
|
+
assert_equal ::Set.new(%w[1 2 3 4 5 6]), set3.to_set, 'should return elements contained in either sets'
|
184
|
+
|
185
|
+
assert_equal ::Set.new(set_contents), @set.to_set, 'should still be the same'
|
186
|
+
assert_equal ::Set.new(set2_contents), set2.to_set, 'should still be the same'
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_to_a
|
190
|
+
values = %w[1 2 3]
|
191
|
+
@set.add(*values)
|
192
|
+
|
193
|
+
assert_equal @set.to_a.sort, values, 'should return an array containing the correct values'
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_to_set
|
197
|
+
values = %w[1 2 3]
|
198
|
+
@set.add(*values)
|
199
|
+
|
200
|
+
assert_equal ::Set.new(values), @set.to_set, 'should return the correct set'
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_each
|
204
|
+
values = %w[a b c d aa]
|
205
|
+
@set.add(*values)
|
206
|
+
|
207
|
+
missing = values.dup
|
208
|
+
@set.each do |word|
|
209
|
+
assert values.include?(word), 'should be in the values'
|
210
|
+
missing.delete(word)
|
211
|
+
end
|
212
|
+
assert_empty missing, 'should not have missed anything'
|
213
|
+
|
214
|
+
matched = ::Set.new
|
215
|
+
@set.each(match: 'a*') { |word| matched << word }
|
216
|
+
assert_equal ::Set.new(%w[a aa]), matched, 'should contain a and aa only'
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
@@ -0,0 +1,219 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module Redstruct
|
6
|
+
class SortedTest < Redstruct::Test
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
@factory = create_factory
|
10
|
+
@set = @factory.sorted_set('zset')
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_initialize
|
14
|
+
refute @set.lexicographic?, 'should not be a lexicographically sorted set'
|
15
|
+
|
16
|
+
lex = @factory.sorted_set('lzset', lex: true)
|
17
|
+
assert lex.lexicographic?, 'should be marked as a lexicographically sorted set'
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_clear
|
21
|
+
assert @set.empty?, 'should initially be empty'
|
22
|
+
@set.add(1, 'a')
|
23
|
+
refute @set.empty?, 'should not be empty'
|
24
|
+
|
25
|
+
assert @set.clear, 'should have been cleared'
|
26
|
+
assert @set.empty?, 'should now be empty again'
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_empty?
|
30
|
+
assert @set.empty?, 'should be empty initially'
|
31
|
+
@set.add(1, 'a')
|
32
|
+
refute @set.empty?, 'should now not be empty'
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_add
|
36
|
+
values = { 1 => 'a', 2 => 'c', 3 => 'b' }
|
37
|
+
assert_equal 3, @set.add(*values.keys.zip(values.values)), 'should have added 3 items'
|
38
|
+
assert_equal 0, @set.add(1, 'a'), 'should not add pre-existing value'
|
39
|
+
assert_equal ::Set.new(%w[a b c]), @set.to_set, 'should contain exactly the values added'
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_add_exists
|
43
|
+
assert_equal 0, @set.add([1, 'a'], exists: true), 'should not have added anything items'
|
44
|
+
assert @set.empty?, 'should not contain anything'
|
45
|
+
|
46
|
+
@set.add([2, 'a'])
|
47
|
+
assert_equal 2.0, @set.score('a'), 'should have score of 2'
|
48
|
+
assert_equal 1, @set.add([1, 'a'], exists: true), 'should have added 1 element'
|
49
|
+
assert_equal 1.0, @set.score('a'), 'should have score of 1'
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_add_overwrite
|
53
|
+
@set.add([2, 'b'])
|
54
|
+
assert_equal 0, @set.add([3, 'b'], overwrite: false), 'should not overwrite pre-existing value'
|
55
|
+
assert_equal 2.0, @set.score('b'), 'should still have old score'
|
56
|
+
assert_equal 1, @set.add([3, 'b'], overwrite: true), 'should have overwritten pre-existing value'
|
57
|
+
assert_equal 3.0, @set.score('b'), 'should now have score of 3'
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_add_lex
|
61
|
+
set = @factory.sorted_set('zset', lex: true)
|
62
|
+
assert_equal 2, set.add([1, 'c'], [2, 'd']), 'should have added 2 elements'
|
63
|
+
assert_equal 2, set.add('a', 'b'), 'should have added 2 elements'
|
64
|
+
|
65
|
+
assert_equal %w[a b c d], set.to_a, 'should be lexicographically sorted'
|
66
|
+
%w[a b c d].each do |letter|
|
67
|
+
assert_equal 0.0, set.score(letter), 'should have a score of 0'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_increment
|
72
|
+
assert_equal 1.0, @set.increment('a'), 'should have a default score of 1.0'
|
73
|
+
assert_equal 3.0, @set.increment('a', by: 2.0), 'should have incremented the score by 2'
|
74
|
+
assert_equal 3.0, @set.score('a'), 'should have the correct score of 3.0'
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_increment_lex
|
78
|
+
set = @factory.sorted_set('zset', lex: true)
|
79
|
+
assert_raises(NotImplementedError, 'should not be able to increment scores for lexicographic sets') do
|
80
|
+
set.increment('a')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_decrement
|
85
|
+
assert_equal(-1.0, @set.decrement('a'), 'should have a default score of -1.0')
|
86
|
+
assert_equal(-3.0, @set.decrement('a', by: 2.0), 'should have decremented the score by 2')
|
87
|
+
assert_equal(-3.0, @set.score('a'), 'should have the correct score of -3.0')
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_decrement_lex
|
91
|
+
set = @factory.sorted_set('zset', lex: true)
|
92
|
+
assert_raises(NotImplementedError, 'should not be able to decrement scores for lexicographic sets') do
|
93
|
+
set.decrement('a')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_size
|
98
|
+
assert_equal 0, @set.size, 'should have a size of 0 initially'
|
99
|
+
@set.add([1, 'a'], [2, 'b'], [3, 'c'])
|
100
|
+
assert_equal 3, @set.size, 'should have a size of 3'
|
101
|
+
end
|
102
|
+
|
103
|
+
# The slice structure has its own tests, so we only test the creation of
|
104
|
+
# a slice here.
|
105
|
+
def test_slice
|
106
|
+
slice = @set.slice
|
107
|
+
assert_equal @set.key, slice.key, 'should have the same object key'
|
108
|
+
assert_equal @set.factory, slice.factory, 'should have the same initial factory'
|
109
|
+
assert_equal '-inf', slice.lower, 'should have infinity as lower bound'
|
110
|
+
assert_equal '+inf', slice.upper, 'should have infinity as upper bound'
|
111
|
+
refute slice.exclusive, 'should not be exclusive by default'
|
112
|
+
|
113
|
+
slice = @set.slice(lower: 1, upper: 3, exclusive: true)
|
114
|
+
assert_equal '(1.0', slice.lower, 'should have exclusive 1.0 as lower bound'
|
115
|
+
assert_equal '(3.0', slice.upper, 'should have exclusive 3.0 as upper bound'
|
116
|
+
|
117
|
+
slice = @set.slice(lower: 1, upper: 3, exclusive: false)
|
118
|
+
assert_equal 1.0, slice.lower, 'should have inclusive 1.0 as lower bound'
|
119
|
+
assert_equal 3.0, slice.upper, 'should have inclusive 3.0 as upper bound'
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_slice_lex
|
123
|
+
set = @factory.sorted_set('zset', lex: true)
|
124
|
+
slice = set.slice
|
125
|
+
assert slice.lex, 'should be a lexicographical slice'
|
126
|
+
assert_equal '-', slice.lower, 'should have lex infinity as lower bound'
|
127
|
+
assert_equal '+', slice.upper, 'should have lex infinity as upper bound'
|
128
|
+
|
129
|
+
slice = set.slice(lower: 'a', upper: 'd', exclusive: true)
|
130
|
+
assert_equal '(a', slice.lower, 'should have exclusive lower bound a'
|
131
|
+
assert_equal '(d', slice.upper, 'should have exclusive upper bound d'
|
132
|
+
|
133
|
+
slice = set.slice(lower: 'a', upper: 'd', exclusive: false)
|
134
|
+
assert_equal '[a', slice.lower, 'should have inclusive lower bound a'
|
135
|
+
assert_equal '[d', slice.upper, 'should have inclusive upper bound d'
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_contain?
|
139
|
+
refute @set.contain?('a'), 'should not contain a initially'
|
140
|
+
@set.add([1, 'a'])
|
141
|
+
assert @set.contain?('a'), 'should now contain a'
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_index
|
145
|
+
assert_nil @set.index('a'), 'should not return any index initially'
|
146
|
+
@set.add([2, 'b'], [1, 'a'])
|
147
|
+
assert_equal 0, @set.index('a'), 'should return correct index for a'
|
148
|
+
assert_equal 1, @set.index('b'), 'should return correct index for b'
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_rindex
|
152
|
+
assert_nil @set.rindex('a'), 'should not return any index initially'
|
153
|
+
@set.add([2, 'b'], [1, 'a'])
|
154
|
+
assert_equal 1, @set.rindex('a'), 'should return correct index for a'
|
155
|
+
assert_equal 0, @set.rindex('b'), 'should return correct index for b'
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_score
|
159
|
+
assert_nil @set.score('a'), 'should return nil when item not in the set'
|
160
|
+
@set.add([1, 'a'])
|
161
|
+
assert_equal 1.0, @set.score('a'), 'should return the correct score'
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_remove
|
165
|
+
items = %w[a b c]
|
166
|
+
assert_equal 0, @set.remove(*items), 'should not have removed anything'
|
167
|
+
|
168
|
+
@set.add(*[1, 2, 3].zip(items))
|
169
|
+
@set.add([4, 'd'])
|
170
|
+
assert_equal 1, @set.remove('d', 'e'), 'should only remove 1 element'
|
171
|
+
assert_equal items, @set.to_a, 'should contain the correct elements'
|
172
|
+
assert_equal 3, @set.remove(*items), 'should have removed all 3 elements'
|
173
|
+
assert @set.empty?, 'should be empty now'
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_to_a
|
177
|
+
assert_empty @set.to_a, 'should initially return an empty array'
|
178
|
+
@set.add([4, 'a'], [3, 'b'], [2, 'c'], [1, 'd'])
|
179
|
+
assert_equal %w[d c b a], @set.to_a, 'should return a sorted array'
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_to_set
|
183
|
+
items = %w[a b]
|
184
|
+
assert_equal ::Set.new, @set.to_set, 'should return an empty set'
|
185
|
+
@set.add(*[1, 2].zip(items))
|
186
|
+
assert_equal ::Set.new(items), @set.to_set, 'should return a set containing the elements'
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_each
|
190
|
+
values = %w[aa b c d a]
|
191
|
+
scores = %w[1 2 3 4 5]
|
192
|
+
sorted = scores.zip(values).sort_by { |pair| pair[0].to_i }
|
193
|
+
@set.add(*sorted)
|
194
|
+
|
195
|
+
received = []
|
196
|
+
@set.each do |word|
|
197
|
+
assert values.include?(word), 'should be in the values'
|
198
|
+
received << word
|
199
|
+
end
|
200
|
+
assert_equal received, @set.to_a, 'should have received it all in order'
|
201
|
+
|
202
|
+
received = []
|
203
|
+
@set.each(match: 'a*') { |word| received << word }
|
204
|
+
assert_equal %w[aa a], received, 'should contain a and aa only'
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_each_with_scores
|
208
|
+
values = %w[aa b c d a]
|
209
|
+
scores = %w[1 2 3 4 5].map(&:to_f)
|
210
|
+
sorted = scores.zip(values).sort_by { |pair| pair[0].to_i }
|
211
|
+
@set.add(*sorted)
|
212
|
+
|
213
|
+
@set.each(with_scores: true).each_with_index do |(value, score), index|
|
214
|
+
assert_equal values[index], value, 'should receive the correct value'
|
215
|
+
assert_equal scores[index], score, 'should receive the correct score'
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
module Redstruct
|
7
|
+
class StructTest < Redstruct::Test
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
@factory = create_factory
|
11
|
+
@struct = @factory.struct('struct')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_initialize
|
15
|
+
key = @factory.prefix(SecureRandom.hex(4))
|
16
|
+
struct = Redstruct::Struct.new(key: key, factory: @factory)
|
17
|
+
assert_equal key, struct.key, 'should have key unchanged after initialization'
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_exists?
|
21
|
+
refute @struct.exists?, 'struct should not yet exist'
|
22
|
+
write_struct
|
23
|
+
assert @struct.exists?, 'struct should exist if underlying redis key exists'
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_delete
|
27
|
+
refute @struct.delete, 'should return false since the struct did not exist'
|
28
|
+
write_struct
|
29
|
+
assert @struct.delete, 'should return true since a key was actually deleted'
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_expire
|
33
|
+
refute @struct.expire(1), 'should return false since no existing key was expired'
|
34
|
+
write_struct
|
35
|
+
assert @struct.expire(1), 'should have correctly expired the existing key'
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_expire_at
|
39
|
+
refute @struct.expire_at(1), 'should return false since no existing key was expired'
|
40
|
+
write_struct
|
41
|
+
assert @struct.expire_at(1), 'should have correctly marked to key to be expired'
|
42
|
+
refute @struct.exists?, 'should not exist since it was marked to be expired 1 second after 1970-01-01'
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_persist; end
|
46
|
+
|
47
|
+
def test_type; end
|
48
|
+
|
49
|
+
def test_ttl; end
|
50
|
+
|
51
|
+
def test_dump; end
|
52
|
+
|
53
|
+
def test_restore; end
|
54
|
+
|
55
|
+
# a struct has no set value, so use the redis connection to "cheat" and set one so the struct actually exists
|
56
|
+
def write_struct
|
57
|
+
@struct.connection.set(@struct.key, 'foo')
|
58
|
+
end
|
59
|
+
private :write_struct
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module Redstruct
|
6
|
+
module Utils
|
7
|
+
class CoercionTest < Redstruct::Test
|
8
|
+
def test_coerce_bool
|
9
|
+
refute Redstruct::Utils::Coercion.coerce_bool(nil), 'nil should be coerced to false'
|
10
|
+
refute Redstruct::Utils::Coercion.coerce_bool(false), 'false should be coerced to false'
|
11
|
+
refute Redstruct::Utils::Coercion.coerce_bool(0), '0 should be coerced to false'
|
12
|
+
refute Redstruct::Utils::Coercion.coerce_bool(0.0), '0.0 should be coerced to false'
|
13
|
+
assert Redstruct::Utils::Coercion.coerce_bool(1), 'any non-zero number should be coerced to true'
|
14
|
+
|
15
|
+
[[], {}, '', true, 3.0, Object.new].each do |value|
|
16
|
+
assert Redstruct::Utils::Coercion.coerce_bool(value), 'should be coerced to true'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_coerce_array
|
21
|
+
assert_equal [], Redstruct::Utils::Coercion.coerce_array(nil), 'nil should be coerced to empty array'
|
22
|
+
|
23
|
+
array = [1, 2, 3]
|
24
|
+
assert_equal array, Redstruct::Utils::Coercion.coerce_array(array), 'array should be returned as is'
|
25
|
+
|
26
|
+
hash = { a: 1, b: 2 }
|
27
|
+
assert_equal hash.to_a, Redstruct::Utils::Coercion.coerce_array(hash), '#to_a should be coerced to its array representation'
|
28
|
+
|
29
|
+
assert_equal [1], Redstruct::Utils::Coercion.coerce_array(1), 'non #to_a should be coerced to an array containing the given value'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'flexmock/minitest'
|
5
|
+
|
6
|
+
module Redstruct
|
7
|
+
module Utils
|
8
|
+
class InspectableTest < Redstruct::Test
|
9
|
+
def test_inspect
|
10
|
+
child = flexmock('test')
|
11
|
+
child.should_receive(:inspect).and_return('child').once
|
12
|
+
other = 'val'
|
13
|
+
|
14
|
+
object = self.class::Test.new(child: child, other: other)
|
15
|
+
assert_equal %(Redstruct::Utils::InspectableTest::Test: child: <child>, other: <"val">), object.inspect, 'should generate the correct inspect string, calling inspect on all values'
|
16
|
+
end
|
17
|
+
|
18
|
+
class Test
|
19
|
+
include Redstruct::Utils::Inspectable
|
20
|
+
|
21
|
+
def initialize(attrs)
|
22
|
+
@attrs = attrs
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspectable_attributes
|
26
|
+
return @attrs
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module Redstruct
|
6
|
+
module Utils
|
7
|
+
class IterableTest < Redstruct::Test
|
8
|
+
def test_to_enum_bad_impl
|
9
|
+
assert_raises(NotImplementedError, 'should fail and raise not implemented on missing implementations') do
|
10
|
+
BadIterator.new.to_enum
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_each_bad_impl
|
15
|
+
assert_raises(NotImplementedError, 'should fail and raise not implemented on missing implementations') do
|
16
|
+
BadIterator.new.each { |o| o }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_each_no_block
|
21
|
+
iterator = self.class::Iterator.new
|
22
|
+
enum = iterator.each # returns an enum
|
23
|
+
|
24
|
+
assert_kind_of Enumerator, enum, 'should return an enumerator when called with no block'
|
25
|
+
assert_equal 0, iterator.iterations, 'should not actually have been called ever yet'
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_each_block
|
29
|
+
iterator = self.class::Iterator.new
|
30
|
+
ones = []
|
31
|
+
|
32
|
+
iterator.each(max_iterations: 2) { |one| ones << one }
|
33
|
+
assert_equal [1, 1], ones, 'should have returned an array of 2 "1"s'
|
34
|
+
end
|
35
|
+
|
36
|
+
# each does not do anything with match or count but pass them on to to_enum, so make sure that this is what we do
|
37
|
+
def test_each_match_count
|
38
|
+
iterator = self.class::Iterator.new
|
39
|
+
_ = iterator.each(match: 'match', count: 1) # returns an enum
|
40
|
+
|
41
|
+
assert_equal 'match', iterator.match, 'should have received the correct match param'
|
42
|
+
assert_equal 1, iterator.count, 'should have received the correct count param'
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_each_max_iterations
|
46
|
+
iterator = self.class::Iterator.new
|
47
|
+
enum = iterator.each(max_iterations: 10)
|
48
|
+
|
49
|
+
assert_equal 10, enum.to_a.size, 'should iterate up to 10 times, therefore containing 10 "1"s in the array'
|
50
|
+
assert_equal 10, iterator.iterations, 'should have iterated exactly 10 times'
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_each_batch_size
|
54
|
+
iterator = self.class::Iterator.new
|
55
|
+
iterator.each(max_iterations: 2, batch_size: 2).each do |ones|
|
56
|
+
assert_equal 2, ones.size, 'should yield in batches of 2 elements'
|
57
|
+
assert_equal [1, 1], ones, 'should yield a list of 2 "1"s'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sample class not implementing interface
|
62
|
+
class BadIterator
|
63
|
+
include Redstruct::Utils::Iterable
|
64
|
+
end
|
65
|
+
|
66
|
+
class Iterator
|
67
|
+
include Redstruct::Utils::Iterable
|
68
|
+
|
69
|
+
attr_reader :iterations, :match, :count
|
70
|
+
|
71
|
+
def initialize
|
72
|
+
@iterations = 0
|
73
|
+
@match = nil
|
74
|
+
@count = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
# the idea is to return an infinite stream of 1s, but monitor how the enum was constructed, and how many
|
78
|
+
# iterations were performed, as opposed to creating a mock object
|
79
|
+
def to_enum(match: '*', count: 10)
|
80
|
+
@match = match
|
81
|
+
@count = count
|
82
|
+
@iterations = 0
|
83
|
+
|
84
|
+
return Enumerator.new do |yielder|
|
85
|
+
loop do
|
86
|
+
@iterations += 1 # increment before yielding, since yielding might immediately raise StopIteration, but we'll still have iterated once
|
87
|
+
yielder << 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|