oklahoma_mixer 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,77 @@
1
+ require "test_helper"
2
+
3
+ class TestFixedLengthTuning < Test::Unit::TestCase
4
+ def teardown
5
+ remove_db_files
6
+ end
7
+
8
+ def test_a_mutex_can_be_activated_as_the_database_is_created
9
+ args = capture_args(OKMixer::FixedLengthDatabase::C, :setmutex) do
10
+ fdb(:mutex => true) do
11
+ # just open and close
12
+ end
13
+ end
14
+ assert_instance_of(FFI::Pointer, args[0])
15
+ assert_equal([ ], args[1..-1])
16
+ end
17
+
18
+ def test_width_controls_value_length
19
+ fdb(:width => 4) do |db|
20
+ db.update(1 => "one", 2 => "two", 3 => "three", 4 => "four")
21
+ assert_equal([[1, "one"], [2, "two"], [3, "thre"], [4, "four"]], db.to_a)
22
+ end
23
+ end
24
+
25
+ def test_width_can_be_changed_later_with_optimize
26
+ fdb do |db| # default width of 255
27
+ db.update(1 => "one", 2 => "two", 3 => "three", 4 => "four")
28
+ assert_equal([[1, "one"], [2, "two"], [3, "three"], [4, "four"]], db.to_a)
29
+ assert(db.optimize(:width => 4), "Width was not changed")
30
+ assert_equal([[1, "one"], [2, "two"], [3, "thre"], [4, "four"]], db.to_a)
31
+ end
32
+ end
33
+
34
+ def test_limsiz_controls_the_maximum_database_size
35
+ fdb(:width => 1024, :limsiz => 3 * 1024) do |db|
36
+ data = "X" * 1024
37
+ assert_nothing_raised(OKMixer::Error::CabinetError) do
38
+ 3.times do |i|
39
+ db[i + 1] = data
40
+ end
41
+ end
42
+ assert_raise(OKMixer::Error::CabinetError) do
43
+ db[4] = "X"
44
+ end
45
+ assert_equal([[1, data], [2, data], [3, data]], db.to_a)
46
+ end
47
+ end
48
+
49
+ def test_limsiz_can_be_increases_later_with_optimize
50
+ fdb(:width => 1024, :limsiz => 3 * 1024) do |db|
51
+ data = "X" * 1024
52
+ 3.times do |i|
53
+ db[i + 1] = data
54
+ end
55
+ assert(db.optimize(:limsiz => 4 * 1024), "Size limit was not increased")
56
+ end
57
+ end
58
+
59
+ def test_defrag_is_a_no_op
60
+ fdb(:width => 1024) do |db|
61
+ # load some data
62
+ data = "X" * 1024
63
+ 10.times do |i|
64
+ db[i + 1] = data
65
+ end
66
+ old_size = File.size(db.path)
67
+ # delete some data
68
+ [3, 5, 7].each do |i|
69
+ db.delete(i)
70
+ end
71
+ assert_equal(old_size, File.size(db.path))
72
+ # no-op
73
+ db.defrag
74
+ assert_equal(old_size, File.size(db.path))
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,288 @@
1
+ require "test_helper"
2
+
3
+ class TestGettingAndSettingByID < Test::Unit::TestCase
4
+ def setup
5
+ @db = fdb
6
+ end
7
+
8
+ def teardown
9
+ @db.close
10
+ remove_db_files
11
+ end
12
+
13
+ def test_a_key_value_pair_can_be_stored_and_fetched_from_the_database
14
+ assert_equal("value", @db.store(42, "value"))
15
+ assert_equal("value", @db.fetch(42)) # later
16
+ end
17
+
18
+ def test_keys_are_converted_to_integers
19
+ assert_equal("value", @db.store(42, "value"))
20
+ assert_equal("value", @db.fetch("42")) # effectively the same key
21
+ end
22
+
23
+ def test_the_special_ids_min_and_max_are_supported_after_ids_are_set
24
+ assert_raise(OKMixer::Error::CabinetError) do
25
+ @db[:min]
26
+ end
27
+ assert_raise(OKMixer::Error::CabinetError) do
28
+ @db[:max]
29
+ end
30
+ @db.update(10 => :min, 20 => :middle, 30 => :max)
31
+ assert_equal("min", @db[:min])
32
+ assert_equal("max", @db[:max])
33
+ end
34
+
35
+ def test_the_special_id_next_can_be_used_to_set_increasing_ids
36
+ 3.times do |n|
37
+ assert_equal(n, @db[:next] = n)
38
+ end
39
+ assert_equal([[1, "0"], [2, "1"], [3, "2"]], @db.to_a)
40
+ @db[7] = 6
41
+ assert_equal(7, @db[:next] = 7)
42
+ assert_equal([[1, "0"], [2, "1"], [3, "2"], [7, "6"], [8, "7"]], @db.to_a)
43
+ end
44
+
45
+ def test_the_special_id_prev_can_be_used_to_add_below_min
46
+ # no min
47
+ assert_raise(OKMixer::Error::CabinetError) do
48
+ @db[:prev] = 100
49
+ end
50
+
51
+ @db[10] = 10
52
+ assert_equal(9, @db[:prev] = 9)
53
+ assert_equal([[9, "9"], [10, "10"]], @db.to_a)
54
+
55
+ # can't go below 1
56
+ @db[1] = 1
57
+ assert_raise(OKMixer::Error::CabinetError) do
58
+ @db[:prev] = 100
59
+ end
60
+ end
61
+
62
+ def test_fetching_a_missing_value_fails_with_an_index_error
63
+ assert_raise(IndexError) do
64
+ @db.fetch(42)
65
+ end
66
+ end
67
+
68
+ def test_fetch_can_return_a_default_for_a_missing_value
69
+ assert_equal(:value, @db.fetch(42, :value))
70
+ end
71
+
72
+ def test_fetch_can_run_a_block_returning_its_result_for_a_missing_value
73
+ assert_equal(42, @db.fetch(42) { |key| key })
74
+ end
75
+
76
+ def test_fetching_with_a_block_overrides_a_default_and_triggers_a_warning
77
+ warning = capture_stderr do
78
+ assert_equal(:returned, @db.fetch(42, :ignored) { :returned })
79
+ end
80
+ assert(!warning.empty?, "A warning was not issued for a default and block")
81
+ end
82
+
83
+ def test_storing_with_keep_mode_adds_a_value_only_if_it_didnt_already_exist
84
+ assert(@db.store(42, :new, :keep), "Failed to store a new key")
85
+ assert_equal("new", @db.fetch(42))
86
+ assert(!@db.store(42, :replace, :keep), "Replaced an existing key")
87
+ assert_equal("new", @db.fetch(42))
88
+ end
89
+
90
+ def test_storing_with_cat_mode_concatenates_content_onto_an_existing_value
91
+ assert_equal("One", @db.store(42, "One", :cat))
92
+ assert_equal("One", @db.fetch(42))
93
+ assert_equal(", Two", @db.store(42, ", Two", :cat))
94
+ assert_equal("One, Two", @db.fetch(42))
95
+ end
96
+
97
+ def test_storing_with_add_mode_adds_to_an_existing_value
98
+ assert_equal(0, @db.store(42, 0, :add))
99
+ assert_equal(1, @db.store(42, 1, :add))
100
+ assert_equal(2, @db.store(42, 1, :add))
101
+ assert_equal(1, @db.store(42, -1, :add))
102
+
103
+ assert_in_delta(1.5, @db.store(100, 1.5, :add), 2 ** -20)
104
+ assert_in_delta(3.5, @db.store(100, 2.0, :add), 2 ** -20)
105
+ assert_in_delta(2.5, @db.store(100, -1.0, :add), 2 ** -20)
106
+ end
107
+
108
+ def test_adding_to_a_non_added_value_fails_with_an_error
109
+ @db[42] = 0
110
+ assert_raise(OKMixer::Error::CabinetError) do
111
+ @db.store(42, 1, :add)
112
+ end
113
+ end
114
+
115
+ def test_switching_add_types_fails_with_an_error
116
+ @db.store(42, 1, :add)
117
+ @db.store(100, 1.0, :add)
118
+ assert_raise(OKMixer::Error::CabinetError) do
119
+ @db.store(42, 2.0, :add)
120
+ end
121
+ assert_raise(OKMixer::Error::CabinetError) do
122
+ @db.store(100, 2, :add)
123
+ end
124
+ end
125
+
126
+ def test_storing_with_a_block_allows_duplicate_resolution
127
+ @db[42] = :old
128
+ assert_equal( :new, @db.store(42, :new) { |key, old, new|
129
+ "#{key}=#{old}&#{new}" } )
130
+ assert_equal("42=old&new", @db[42])
131
+ end
132
+
133
+ def test_storing_with_a_block_overrides_a_mode_and_triggers_a_warning
134
+ warning = capture_stderr do
135
+ assert_equal(:new, @db.store(42, :new, :cat) { |key, old, new| })
136
+ end
137
+ assert(!warning.empty?, "A warning was not issued for a mode and block")
138
+ end
139
+
140
+ def test_storing_with_a_mode_not_supported_by_the_database_triggers_a_warning
141
+ warning = capture_stderr do
142
+ assert_equal(:value, @db.store(42, :value, :async)) # normal store
143
+ end
144
+ assert(!warning.empty?, "A warning was not issued for an unsupported mode")
145
+ assert_equal("value", @db[42])
146
+ end
147
+
148
+ def test_store_and_fetch_can_also_be_used_through_the_indexing_brackets
149
+ assert_equal(:value, @db[42] = :value)
150
+ assert_equal("value", @db[42])
151
+ end
152
+
153
+ def test_indexing_returns_nil_instead_of_failing_with_index_error
154
+ assert_nil(@db[42])
155
+ end
156
+
157
+ def test_a_default_can_be_set_for_indexing_to_return
158
+ @db.default = :default
159
+ assert_equal(:default, @db[42])
160
+ end
161
+
162
+ def test_the_indexing_default_will_be_run_if_it_is_a_proc
163
+ @db.default = lambda { |key| "is #{key}" }
164
+ assert_equal("is 42", @db[42])
165
+ end
166
+
167
+ def test_the_indexing_default_for_a_given_key_can_be_retrieved
168
+ @db.default = lambda { |key| "is #{key}" }
169
+ assert_equal("is ", @db.default)
170
+ assert_equal("is 42", @db.default(42))
171
+ end
172
+
173
+ def test_the_indexing_default_can_be_changed
174
+ assert_nil(@db[42])
175
+ assert_equal(:default, @db.default = :default)
176
+ assert_equal(:default, @db[:missing])
177
+ proc = lambda { |key| fail RuntimeError, "%p not found" % [key]}
178
+ assert_equal(proc, @db.default = proc)
179
+ error = assert_raise(RuntimeError) { @db[42] }
180
+ assert_equal("42 not found", error.message)
181
+ end
182
+
183
+ def test_include_and_aliases_can_be_used_to_check_for_the_existance_of_a_key
184
+ @db[42] = true
185
+ %w[include? has_key? key? member?].each do |query|
186
+ assert(@db.send(query, 42), "Failed to detect an existing key")
187
+ assert(!@db.send(query, 100), "Failed to detect an missing key")
188
+ end
189
+ end
190
+
191
+ def test_update_sets_multiple_values_at_once_overwriting_old_values
192
+ @db[42] = "old_42"
193
+ assert_equal(@db, @db.update(1 => "new_1", 42 => "new_42", 3 => "new_3"))
194
+ assert_equal(%w[new_1 new_42 new_3], @db.values_at(1, 42, 3))
195
+ end
196
+
197
+ def test_update_can_be_passed_a_block_for_handling_duplicates
198
+ @db[42] = "old"
199
+ assert_equal( @db, @db.update( 1 => "new",
200
+ 42 => "new",
201
+ 3 => "new") { |key, old, new|
202
+ "#{key}=#{old}&#{new}" } )
203
+ assert_equal(%w[new 42=old&new new], @db.values_at(1, 42, 3))
204
+ end
205
+
206
+ def test_values_at_can_be_used_to_retrieve_multiple_values_at_once
207
+ @db[1] = 100
208
+ @db[3] = 300
209
+ assert_equal([ ], @db.values_at)
210
+ assert_equal(["100", nil, "300"], @db.values_at(1, 42, 3))
211
+ end
212
+
213
+ def test_values_at_supports_defaults
214
+ @db.default = 42
215
+ @db[1] = 100
216
+ @db[3] = 300
217
+ assert_equal(["100", 42, "300"], @db.values_at(1, 42, 3))
218
+ end
219
+
220
+ def test_keys_returns_all_keys_in_the_database
221
+ @db.update(1 => 100, 2 => 200, 3 => 300)
222
+ assert_equal([1, 2, 3], @db.keys)
223
+ end
224
+
225
+ def test_keys_does_not_support_prefix_for_fixed_length_databases
226
+ assert_raise(ArgumentError) do
227
+ @db.keys(:prefix => "1")
228
+ end
229
+ end
230
+
231
+ def test_keys_can_take_a_limit_of_keys_to_return
232
+ @db.update(1 => 100, 42 => 4200, 3 => 300)
233
+ assert_equal([1, 3], @db.keys(:limit => 2))
234
+ end
235
+
236
+ def test_values_returns_all_values_in_the_database
237
+ @db.update(1 => 100, 2 => 200, 3 => 300)
238
+ assert_equal(%w[100 200 300], @db.values)
239
+ end
240
+
241
+ def test_delete_removes_a_key_from_the_database
242
+ @db[42] = :value
243
+ assert_equal("value", @db.delete(42))
244
+ assert_nil(@db[42])
245
+ end
246
+
247
+ def test_delete_returns_nil_for_a_missing_key
248
+ assert_nil(@db.delete(42))
249
+ end
250
+
251
+ def test_delete_can_be_passed_a_block_to_handle_missing_keys
252
+ assert_equal(:value, @db.delete(42) { :value })
253
+ end
254
+
255
+ def test_clear_removes_all_keys_from_the_database
256
+ @db.update(1 => 100, 2 => 200, 3 => 300)
257
+ assert_equal(@db, @db.clear)
258
+ assert_equal([nil, nil, nil], @db.values_at(1, 2, 3))
259
+ end
260
+
261
+ def test_size_and_length_return_the_count_of_key_value_pairs_in_the_database
262
+ assert_equal(0, @db.size)
263
+ assert_equal(0, @db.length)
264
+ @db.update(1 => 100, 2 => 200, 3 => 300)
265
+ assert_equal(3, @db.size)
266
+ assert_equal(3, @db.length)
267
+ end
268
+
269
+ def test_each_key_iterates_over_ids
270
+ @db.update(1 => 100, 2 => 200, 3 => 300)
271
+ keys = [1, 2, 3]
272
+ @db.each_key do |key|
273
+ assert_equal(keys.shift, key)
274
+ end
275
+ end
276
+
277
+ def test_each_and_each_pair_iterate_over_ids_and_values
278
+ @db.update(1 => 100, 2 => 200, 3 => 300)
279
+ %w[each each_pair].each do |iterator|
280
+ keys = [1, 2, 3]
281
+ values = %w[100 200 300]
282
+ @db.send(iterator) do |key, value|
283
+ assert_equal(keys.shift, key)
284
+ assert_equal(values.shift, value)
285
+ end
286
+ end
287
+ end
288
+ end
@@ -68,12 +68,30 @@ class TestGettingAndSettingKeys < Test::Unit::TestCase
68
68
  assert_equal(1, @db.store(:i, 1, :add))
69
69
  assert_equal(2, @db.store(:i, 1, :add))
70
70
  assert_equal(1, @db.store(:i, -1, :add))
71
-
71
+
72
72
  assert_in_delta(1.5, @db.store(:f, 1.5, :add), 2 ** -20)
73
73
  assert_in_delta(3.5, @db.store(:f, 2.0, :add), 2 ** -20)
74
74
  assert_in_delta(2.5, @db.store(:f, -1.0, :add), 2 ** -20)
75
75
  end
76
76
 
77
+ def test_adding_to_a_non_added_value_fails_with_an_error
78
+ @db[:i] = 42
79
+ assert_raise(OKMixer::Error::CabinetError) do
80
+ @db.store(:i, 1, :add)
81
+ end
82
+ end
83
+
84
+ def test_switching_add_types_fails_with_an_error
85
+ @db.store(:i, 1, :add)
86
+ @db.store(:f, 1.0, :add)
87
+ assert_raise(OKMixer::Error::CabinetError) do
88
+ @db.store(:i, 2.0, :add)
89
+ end
90
+ assert_raise(OKMixer::Error::CabinetError) do
91
+ @db.store(:f, 2, :add)
92
+ end
93
+ end
94
+
77
95
  def test_storing_with_a_block_allows_duplicate_resolution
78
96
  @db[:key] = :old
79
97
  assert_equal( :new, @db.store(:key, :new) { |key, old, new|
@@ -88,6 +106,22 @@ class TestGettingAndSettingKeys < Test::Unit::TestCase
88
106
  assert(!warning.empty?, "A warning was not issued for a mode and block")
89
107
  end
90
108
 
109
+ def test_storing_with_a_mode_not_supported_by_the_database_triggers_a_warning
110
+ warning = capture_stderr do
111
+ assert_equal(:one, @db.store(:dups, :one, :dup)) # normal store
112
+ end
113
+ assert(!warning.empty?, "A warning was not issued for an unsupported mode")
114
+ assert_equal("one", @db[:dups])
115
+
116
+ bdb do |db|
117
+ warning = capture_stderr do
118
+ assert_equal(:value, db.store(:key, :value, :async)) # normal store
119
+ end
120
+ assert(!warning.empty?, "A warning was not issued for an unsupported mode")
121
+ assert_equal("value", db[:key])
122
+ end
123
+ end
124
+
91
125
  def test_store_and_fetch_can_also_be_used_through_the_indexing_brackets
92
126
  assert_equal(42, @db[:num] = 42)
93
127
  assert_equal("42", @db[:num])
@@ -155,8 +189,8 @@ class TestGettingAndSettingKeys < Test::Unit::TestCase
155
189
 
156
190
  def test_values_at_supports_defaults
157
191
  @db.default = 42
158
- @db[:a] = 1
159
- @db[:c] = 2
192
+ @db[:a] = 1
193
+ @db[:c] = 2
160
194
  assert_equal(["1", 42, "2"], @db.values_at(:a, :b, :c))
161
195
  end
162
196
 
@@ -1,4 +1,5 @@
1
1
  require "test_helper"
2
+ require "shared_iteration"
2
3
 
3
4
  class TestIteration < Test::Unit::TestCase
4
5
  def setup
@@ -15,80 +16,5 @@ class TestIteration < Test::Unit::TestCase
15
16
  remove_db_files
16
17
  end
17
18
 
18
- def test_each_key_iterates_over_all_keys_in_the_database
19
- @db.each_key do |key|
20
- @keys.delete(key)
21
- end
22
- assert(@keys.empty?, "All keys were not iterated over")
23
- end
24
-
25
- def test_each_iterates_over_all_key_value_pairs_in_arrays
26
- @db.each do |key_value_array|
27
- assert_instance_of(Array, key_value_array)
28
- assert_equal(2, key_value_array.size)
29
- key, value = key_value_array
30
- assert_equal(key * 2, value)
31
- @keys.delete(key)
32
- @values.delete(value)
33
- end
34
- assert( @keys.empty? && @values.empty?,
35
- "All key/value pairs were not iterated over" )
36
- end
37
-
38
- def test_the_arrays_passed_to_each_can_be_split
39
- @db.each do |key, value|
40
- @keys.delete(key)
41
- @values.delete(value)
42
- end
43
- assert( @keys.empty? && @values.empty?,
44
- "All key/value pairs were not iterated over" )
45
- end
46
-
47
- def test_each_pair_is_an_alias_for_each
48
- each_arrays = [ ]
49
- @db.each do |array|
50
- each_arrays << array
51
- end
52
- @db.each_pair do |array|
53
- each_arrays.delete(array)
54
- end
55
- each_keys_and_values = [ ]
56
- @db.each do |key, value|
57
- each_keys_and_values << [key, value]
58
- end
59
- @db.each_pair do |key, value|
60
- each_keys_and_values.delete([key, value])
61
- end
62
- assert( each_arrays.empty? && each_keys_and_values.empty?,
63
- "The iterations did not match" )
64
- end
65
-
66
- def test_each_value_iterates_over_all_values_in_the_database
67
- @db.each_value do |value|
68
- @values.delete(value)
69
- end
70
- assert(@values.empty?, "All values were not iterated over")
71
- end
72
-
73
- def test_the_standard_iterators_are_supported
74
- assert_kind_of(Enumerable, @db)
75
-
76
- # examples
77
- assert_equal(%w[b bb], @db.find { |_, value| value == "bb" })
78
- assert_nil(@db.find { |_, value| value == "dd" })
79
- assert_equal(%w[aaa bbb ccc], @db.map { |key, value| key + value }.sort)
80
- assert( @db.any? { |_, value| value.include? "c" },
81
- "A value was not found during iteration" )
82
- end
83
-
84
- def test_delete_if_removes_all_keys_for_which_the_block_returns_true
85
- @db.delete_if { |key, _| key != "a" }
86
- assert_equal([%w[a aa]], @db.to_a)
87
- end
88
-
89
- def test_iterators_return_self_to_match_hash_interface
90
- %w[each_key each each_pair each_value delete_if].each do |iterator|
91
- assert_equal(@db, @db.send(iterator) { })
92
- end
93
- end
19
+ include SharedIteration
94
20
  end