perobs 3.0.2 → 4.0.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.
@@ -1,4 +1,4 @@
1
1
  module PEROBS
2
2
  # The version number
3
- VERSION = "3.0.2"
3
+ VERSION = "4.0.0"
4
4
  end
data/test/Array_spec.rb CHANGED
@@ -33,7 +33,7 @@ require 'perobs'
33
33
 
34
34
  class PO < PEROBS::Object
35
35
 
36
- po_attr :name
36
+ attr_persist :name
37
37
 
38
38
  def initialize(store, name = nil)
39
39
  super(store)
@@ -65,7 +65,7 @@ describe PEROBS::Array do
65
65
  @store.transaction do
66
66
  @store['b'] = @store.new(PEROBS::Array)
67
67
  end
68
- @store.sync
68
+ @store.exit
69
69
  @store = nil
70
70
  GC.start
71
71
 
@@ -85,7 +85,7 @@ describe PEROBS::Array do
85
85
  expect(a[0]).to eq('A')
86
86
  expect(a[1]).to eq('B')
87
87
  expect(a[2].name).to eq('foobar')
88
- @store.sync
88
+ @store.exit
89
89
 
90
90
  @store = PEROBS::Store.new(@db_name)
91
91
  a = @store['a']
@@ -102,7 +102,7 @@ describe PEROBS::Array do
102
102
  vs = ''
103
103
  a.each { |v| vs << v }
104
104
  expect(vs).to eq('ABC')
105
- @store.sync
105
+ @store.exit
106
106
 
107
107
  @store = PEROBS::Store.new(@db_name)
108
108
  a = @store['a']
@@ -113,15 +113,15 @@ describe PEROBS::Array do
113
113
  end
114
114
 
115
115
  # Utility method to create a PEROBS::Array from a normal Array.
116
- def cpa(ary = nil)
116
+ def cpa(ary = nil, id = 'a')
117
117
  a = @store.new(PEROBS::Array)
118
118
  a.replace(ary) unless ary.nil?
119
- @store['a'] = a
119
+ @store[id] = a
120
120
  end
121
121
 
122
122
  def pcheck
123
123
  yield
124
- @store.sync
124
+ @store.exit
125
125
  @store = PEROBS::Store.new(@db_name)
126
126
  yield
127
127
  end
@@ -147,44 +147,44 @@ describe PEROBS::Array do
147
147
  it 'should support re-writing methods' do
148
148
  x = cpa([2, 5, 3, 1, 7])
149
149
  x.sort!{ |a, b| a <=> b }
150
- pcheck { expect(x).to eq([ 1, 2, 3, 5, 7 ]) }
151
- x.sort!{ |a, b| b - a }
152
- pcheck { expect(x).to eq([ 7, 5, 3, 2, 1 ]) }
150
+ pcheck { expect(@store['a']).to eq([ 1, 2, 3, 5, 7 ]) }
151
+ @store['a'].sort!{ |a, b| b - a }
152
+ pcheck { expect(@store['a']).to eq([ 7, 5, 3, 2, 1 ]) }
153
153
 
154
- x.clear
155
- pcheck { expect(x).to eq([]) }
154
+ @store['a'].clear
155
+ pcheck { expect(@store['a']).to eq([]) }
156
156
  end
157
157
 
158
158
  it 'should support <<()' do
159
159
  a = cpa([ 0, 1, 2 ])
160
160
  a << 4
161
- pcheck { expect(a).to eq([ 0, 1, 2, 4 ]) }
161
+ pcheck { expect(@store['a']).to eq([ 0, 1, 2, 4 ]) }
162
162
  end
163
163
 
164
164
  it 'should support []=' do
165
165
  a = cpa([ 0, nil, 2 ])
166
166
  a[1] = 1
167
- pcheck { expect(a).to eq([ 0, 1, 2 ]) }
167
+ pcheck { expect(@store['a']).to eq([ 0, 1, 2 ]) }
168
168
  end
169
169
 
170
170
  it 'should support collect!()' do
171
171
  a = cpa([ 1, 'cat', 1..1 ])
172
- expect(a.collect! { |e| e.class }).to eq([ Integer, String, Range ])
173
- pcheck { expect(a).to eq([ Integer, String, Range ]) }
172
+ expect(a.collect! { |e| e.class.to_s }).to eq([ 'Integer', 'String', 'Range' ])
173
+ pcheck { expect(@store['a'].to_a).to eq([ 'Integer', 'String', 'Range' ]) }
174
174
 
175
175
  a = cpa([ 1, 'cat', 1..1 ])
176
176
  expect(a.collect! { 99 }).to eq([ 99, 99, 99])
177
- pcheck { expect(a).to eq([ 99, 99, 99]) }
177
+ pcheck { expect(@store['a']).to eq([ 99, 99, 99]) }
178
178
  end
179
179
 
180
180
  it 'should support map!()' do
181
181
  a = cpa([ 1, 'cat', 1..1 ])
182
- expect(a.map! { |e| e.class }).to eq([ Integer, String, Range ])
183
- pcheck { expect(a).to eq([ Integer, String, Range ]) }
182
+ expect(a.map! { |e| e.class.to_s }).to eq([ 'Integer', 'String', 'Range' ])
183
+ pcheck { expect(@store['a']).to eq([ 'Integer', 'String', 'Range' ]) }
184
184
 
185
185
  a = cpa([ 1, 'cat', 1..1 ])
186
186
  expect(a.map! { 99 }).to eq([ 99, 99, 99])
187
- pcheck { expect(a).to eq ([ 99, 99, 99]) }
187
+ pcheck { expect(@store['a']).to eq ([ 99, 99, 99]) }
188
188
  end
189
189
 
190
190
  it 'should support fill()' do
@@ -194,39 +194,39 @@ describe PEROBS::Array do
194
194
  end
195
195
 
196
196
  it 'should support flatten!()' do
197
- a1 = cpa([ 1, 2, 3])
198
- a2 = cpa([ 5, 6 ])
199
- a3 = cpa([ 4, a2 ])
200
- a4 = cpa([ a1, a3 ])
201
- pcheck { expect(a4.flatten).to eq([ 1, 2, 3, 4, 5, 6 ]) }
197
+ a1 = cpa([ 1, 2, 3], 'a1')
198
+ a2 = cpa([ 5, 6 ], 'a2')
199
+ a3 = cpa([ 4, a2 ], 'a3')
200
+ a4 = cpa([ a1, a3 ], 'a4')
201
+ pcheck { expect(@store['a4'].flatten).to eq([ 1, 2, 3, 4, 5, 6 ]) }
202
202
  end
203
203
 
204
204
  it 'should support replace()' do
205
- a = cpa([ 1, 2, 3])
206
- a_id = a.__id__
207
- expect(a.replace(cpa([4, 5, 6]))).to eq([ 4, 5, 6 ])
208
- pcheck { expect(a).to eq ([ 4, 5, 6 ]) }
205
+ a1 = cpa([ 1, 2, 3], 'a1')
206
+ a_id = a1.__id__
207
+ expect(a1.replace(cpa([4, 5, 6], 'a2'))).to eq([ 4, 5, 6 ])
208
+ pcheck { expect(@store['a1']).to eq ([ 4, 5, 6 ]) }
209
209
  end
210
210
 
211
211
  it 'should support insert()' do
212
212
  a = cpa([ 0 ])
213
213
  a.insert(1)
214
- pcheck { expect(a).to eq([ 0 ]) }
215
- a.insert(1, 1)
216
- pcheck { expect(a).to eq([ 0, 1]) }
214
+ pcheck { expect(@store['a']).to eq([ 0 ]) }
215
+ @store['a'].insert(1, 1)
216
+ pcheck { expect(@store['a']).to eq([ 0, 1]) }
217
217
  end
218
218
 
219
219
  it 'should support push()' do
220
220
  a = cpa([ 1, 2, 3 ])
221
221
  a.push(4, 5)
222
- pcheck { expect(a).to eq([ 1, 2, 3, 4, 5 ]) }
223
- a.push(nil)
224
- pcheck { expect(a).to eq([ 1, 2, 3, 4, 5, nil ]) }
222
+ pcheck { expect(@store['a']).to eq([ 1, 2, 3, 4, 5 ]) }
223
+ @store['a'].push(nil)
224
+ pcheck { expect(@store['a']).to eq([ 1, 2, 3, 4, 5, nil ]) }
225
225
  end
226
226
 
227
227
  it 'should support inspect' do
228
- a1 = cpa([ 1 ])
229
- a2 = cpa([ 1, a1 ])
228
+ a1 = cpa([ 1 ], 'a1')
229
+ a2 = cpa([ 1, a1 ], 'a2')
230
230
  expect(a1.inspect).to eq("<PEROBS::Array:#{a1._id}>\n[\n 1\n]\n")
231
231
  expect(a2.inspect).to eq("<PEROBS::Array:#{a2._id}>\n[\n 1,\n <PEROBS::ObjectBase:#{a1._id}>\n]\n")
232
232
  end
@@ -244,7 +244,7 @@ describe PEROBS::Array do
244
244
  o = @store.new(PO)
245
245
  a[0] = o.get_self
246
246
  PEROBS.log.open(StringIO.new)
247
- expect { @store.sync }.to raise_error(PEROBS::FatalError)
247
+ expect { @store.exit }.to raise_error(PEROBS::FatalError)
248
248
  PEROBS.log.open($stderr)
249
249
  end
250
250
 
data/test/BTree_spec.rb CHANGED
@@ -125,4 +125,49 @@ describe PEROBS::BTree do
125
125
  end
126
126
  end
127
127
 
128
+ it 'should survive a real-world usage test' do
129
+ @m.clear
130
+ ref = {}
131
+ 0.upto(50000) do
132
+ case rand(5)
133
+ when 0
134
+ 0.upto(2) do
135
+ key = rand(100000)
136
+ value = rand(10000000)
137
+ @m.insert(key, value)
138
+ ref[key] = value
139
+ end
140
+ when 1
141
+ if ref.length > 0
142
+ key = ref.keys[rand(ref.keys.length)]
143
+ expect(@m.remove(key)).to eql(ref[key])
144
+ ref.delete(key)
145
+ end
146
+ when 2
147
+ if ref.length > 0
148
+ 0.upto(3) do
149
+ key = ref.keys[rand(ref.keys.length)]
150
+ expect(@m.get(key)).to eql(ref[key])
151
+ end
152
+ end
153
+ when 3
154
+ if ref.length > 0
155
+ key = ref.keys[rand(ref.keys.length)]
156
+ value = rand(10000000)
157
+ @m.insert(key, value)
158
+ ref[key] = value
159
+ end
160
+ when 4
161
+ if rand(50) == 0
162
+ expect(@m.check).to be true
163
+ end
164
+ when 5
165
+ if rand(50) == 0
166
+ @m.close
167
+ @m.open
168
+ end
169
+ end
170
+ end
171
+ end
172
+
128
173
  end
@@ -179,10 +179,6 @@ describe PEROBS::EquiBlobsFile do
179
179
  expect(@bf.check).to be true
180
180
  end
181
181
 
182
- it 'should not allow erase when open' do
183
- expect{ capture_io{ @bf.erase } }.to raise_error(PEROBS::FatalError)
184
- end
185
-
186
182
  it 'should support erasing the file' do
187
183
  @bf.close
188
184
  @bf.erase
@@ -31,7 +31,7 @@ require 'perobs/Store'
31
31
 
32
32
  class FlatFileDB_O < PEROBS::Object
33
33
 
34
- po_attr :a, :b, :c
34
+ attr_persist :a, :b, :c
35
35
 
36
36
  def initialize(store)
37
37
  super
data/test/Hash_spec.rb CHANGED
@@ -34,7 +34,7 @@ require 'perobs'
34
34
 
35
35
  class PO < PEROBS::Object
36
36
 
37
- po_attr :name
37
+ attr_persist :name
38
38
 
39
39
  def initialize(store, name = nil)
40
40
  super(store)
@@ -71,7 +71,7 @@ describe PEROBS::Hash do
71
71
 
72
72
  expect(h['a']).to eq('A')
73
73
  expect(h['b']).to eq('B')
74
- @store.sync
74
+ @store.exit
75
75
 
76
76
  @store = PEROBS::Store.new(@db_name)
77
77
  h = @store['h']
@@ -88,6 +88,7 @@ describe PEROBS::Hash do
88
88
  vs = []
89
89
  h.each { |k, v| vs << k + v }
90
90
  expect(vs.sort.join).to eq('aAbBcC')
91
+ @store.exit
91
92
 
92
93
  @store = PEROBS::Store.new(@db_name)
93
94
  @store['h'] = h = @store.new(PEROBS::Hash)
@@ -100,15 +101,15 @@ describe PEROBS::Hash do
100
101
  end
101
102
 
102
103
  # Utility method to create a PEROBS::Hash from a normal Hash.
103
- def cph(hash = nil)
104
+ def cph(hash = nil, id = 'a')
104
105
  a = @store.new(PEROBS::Hash)
105
106
  a.replace(hash) unless hash.nil?
106
- @store['a'] = a
107
+ @store[id] = a
107
108
  end
108
109
 
109
110
  def pcheck
110
111
  yield
111
- @store.sync
112
+ @store.exit
112
113
  @store = PEROBS::Store.new(@db_name)
113
114
  yield
114
115
  end
@@ -142,20 +143,20 @@ describe PEROBS::Hash do
142
143
  end
143
144
 
144
145
  it 'should support merge!' do
145
- h1 = cph({ 1 => 2, 2 => 3, 3 => 4 })
146
- h2 = cph({ 2 => 'two', 4 => 'four' })
146
+ h1 = cph({ '1' => 2, '2' => 3, '3' => 4 }, 'h1')
147
+ h2 = cph({ '2' => 'two', '4' => 'four' }, 'h2')
147
148
 
148
- ha = { 1 => 2, 2 => 'two', 3 => 4, 4 => 'four' }
149
- hb = { 1 => 2, 2 => 3, 3 => 4, 4 => 'four' }
149
+ ha = { '1' => 2, '2' => 'two', '3' => 4, '4' => 'four' }
150
+ hb = { '1' => 2, '2' => 3, '3' => 4, '4' => 'four' }
150
151
 
151
152
  expect(h1.update(h2)).to eq(ha)
152
- pcheck { expect(h1).to eq(ha) }
153
+ pcheck { expect(@store['h1'].to_hash).to eq(ha) }
153
154
 
154
- h1 = cph({ 1 => 2, 2 => 3, 3 => 4 })
155
- h2 = cph({ 2 => 'two', 4 => 'four' })
155
+ h1 = cph({ '1' => 2, '2' => 3, '3' => 4 }, 'h1')
156
+ h2 = cph({ '2' => 'two', '4' => 'four' }, 'h2')
156
157
 
157
158
  expect(h2.update(h1)).to eq(hb)
158
- pcheck { expect(h2).to eq(hb) }
159
+ pcheck { expect(@store['h2'].to_hash).to eq(hb) }
159
160
  end
160
161
 
161
162
  it 'should support inspect' do
data/test/Object_spec.rb CHANGED
@@ -28,7 +28,7 @@ require 'perobs'
28
28
 
29
29
  class O1_Object < PEROBS::Object
30
30
 
31
- po_attr :a1
31
+ attr_persist :a1
32
32
 
33
33
  def initialize(store)
34
34
  super
@@ -38,7 +38,7 @@ end
38
38
 
39
39
  class O2_Object < PEROBS::Object
40
40
 
41
- po_attr :a1, :a2, :a3, :a4
41
+ attr_persist :a1, :a2, :a3, :a4
42
42
 
43
43
  def initialize(store)
44
44
  super
@@ -99,7 +99,7 @@ describe PEROBS::Store do
99
99
  expect(o2.a1).to be_nil
100
100
  expect(o2.a3).to eq(o1)
101
101
  expect(o2.a4).to eq(42)
102
- @store.sync
102
+ @store.exit
103
103
  end
104
104
 
105
105
  it 'should persist assigned values' do
@@ -114,7 +114,7 @@ describe PEROBS::Store do
114
114
  @store['o3'] = o3 = @store.new(O1_Object)
115
115
  o3.a1 = @store.new(PEROBS::Array)
116
116
  end
117
- @store.sync
117
+ @store.exit
118
118
  @store = nil
119
119
  GC.start
120
120
 
@@ -163,7 +163,7 @@ describe PEROBS::Store do
163
163
  it 'should raise an error when no attributes are defined' do
164
164
  @store['o3'] = @store.new(O3)
165
165
  PEROBS.log.open(StringIO.new)
166
- expect { @store.sync }.to raise_error(PEROBS::FatalError)
166
+ expect { @store.exit }.to raise_error(PEROBS::FatalError)
167
167
  PEROBS.log.open($stderr)
168
168
  end
169
169
 
data/test/Store_spec.rb CHANGED
@@ -31,7 +31,7 @@ end
31
31
 
32
32
  class Person < PEROBS::Object
33
33
 
34
- po_attr :name, :zip, :bmi, :married, :related, :relatives
34
+ attr_persist :name, :zip, :bmi, :married, :related, :relatives
35
35
 
36
36
  def initialize(store)
37
37
  super
@@ -44,7 +44,7 @@ end
44
44
 
45
45
  class PersonN < PEROBS::Object
46
46
 
47
- po_attr :name, :zip, :bmi, :married, :related, :relatives
47
+ attr_persist :name, :zip, :bmi, :married, :related, :relatives
48
48
 
49
49
  def initialize(store)
50
50
  super
@@ -57,7 +57,7 @@ end
57
57
 
58
58
  class O0 < PEROBS::Object
59
59
 
60
- po_attr :child
60
+ attr_persist :child
61
61
 
62
62
  def initialize(store)
63
63
  super
@@ -67,7 +67,7 @@ class O0 < PEROBS::Object
67
67
  end
68
68
  class O1 < PEROBS::Object
69
69
 
70
- po_attr :parent
70
+ attr_persist :parent
71
71
 
72
72
  def initialize(store, p = nil)
73
73
  super(store)
@@ -130,7 +130,7 @@ describe PEROBS::Store do
130
130
  jane.married = true
131
131
  jane.relatives = 'test'
132
132
 
133
- @store.sync
133
+ @store.exit
134
134
 
135
135
  @store = PEROBS::Store.new(@db_file)
136
136
  john = @store['john']
@@ -175,7 +175,7 @@ describe PEROBS::Store do
175
175
  jane.married = true
176
176
  jane.relatives = 'test'
177
177
 
178
- @store.sync
178
+ @store.exit
179
179
 
180
180
  @store = PEROBS::Store.new(@db_file)
181
181
  @store.rename_classes({ 'Person' => 'PersonN' })
@@ -200,7 +200,7 @@ describe PEROBS::Store do
200
200
  0.upto(20) do |i|
201
201
  @store["person#{i}"].name = "New Person #{i}"
202
202
  end
203
- @store.sync
203
+ @store.exit
204
204
  @store = PEROBS::Store.new(@db_file)
205
205
  0.upto(20) do |i|
206
206
  expect(@store["person#{i}"].name).to eq("New Person #{i}")
@@ -218,6 +218,7 @@ describe PEROBS::Store do
218
218
  @store.sync
219
219
  @store['person1'] = nil
220
220
  @store.gc
221
+ @store.exit
221
222
  @store = PEROBS::Store.new(@db_file)
222
223
  expect(@store.object_by_id(id1)).to be_nil
223
224
  expect(@store['person2']._id).to eq(id2)
@@ -238,6 +239,7 @@ describe PEROBS::Store do
238
239
  expect(@store.check).to eq(0)
239
240
  expect(@store.gc).to eq(0)
240
241
  p0 = p1 = p2 = nil
242
+ @store.exit
241
243
  GC.start
242
244
  @store = PEROBS::Store.new(@db_file)
243
245
  expect(@store['person0']._id).to eq(id0)
@@ -249,6 +251,7 @@ describe PEROBS::Store do
249
251
  GC.start
250
252
  expect(@store.object_by_id(id1)).to be_nil
251
253
  expect(@store.object_by_id(id2)).to be_nil
254
+ @store.exit
252
255
 
253
256
  @store = PEROBS::Store.new(@db_file)
254
257
  expect(@store.check).to eq(0)
@@ -432,43 +435,83 @@ describe PEROBS::Store do
432
435
  @store['root'] = @store.new(O0)
433
436
  @store.sync
434
437
  expect(@store.check).to eq(0)
438
+ @store.exit
435
439
 
436
440
  @store = PEROBS::Store.new(@db_file)
437
441
  expect(@store.check).to eq(0)
438
442
  expect(@store['root'].child.parent).to eq(@store['root'])
439
443
  end
440
444
 
445
+ it 'should handle frequent updates of objects' do
446
+ @store = PEROBS::Store.new(@db_file)
447
+ count = 10000
448
+ 0.upto(count) do |i|
449
+ key = "Obj#{i}"
450
+ @store[key] = p = @store.new(Person)
451
+ p.name = "0:#{i}:" + 'X' * rand(64)
452
+ end
453
+
454
+ 0.upto(10) do |iteration|
455
+ 0.upto(count) do |i|
456
+ key = "Obj#{i}"
457
+ p = @store[key]
458
+ p.name = "#{iteration}:#{i}:" + 'X' * rand(64)
459
+ end
460
+ 0.upto(count) do |i|
461
+ key = "Obj#{i}"
462
+ p = @store[key]
463
+ o_it, o_i, o_x = p.name.split(':')
464
+ if o_it.to_i != iteration
465
+ $stderr.puts "Mismatch of #{p._id} with value #{o_it}:#{i}"
466
+ end
467
+ expect(o_it.to_i).to eql(iteration)
468
+ expect(o_i.to_i).to eql(i)
469
+ end
470
+ @store.check
471
+ end
472
+ end
473
+
441
474
  it 'should survive a real world usage test' do
442
475
  options = { :engine => PEROBS::FlatFileDB }
443
476
  @store = PEROBS::Store.new(@db_file, options)
444
477
  ref = {}
445
478
 
446
479
  deletions_since_last_gc = 0
447
- 0.upto(15000) do |i|
480
+ 0.upto(10000) do |i|
448
481
  key = "o#{i}"
449
- case rand(8)
482
+ case rand(9)
450
483
  when 0
451
484
  # Add 'A' person
452
- value = 'A' * rand(512)
485
+ value = key + 'A' * rand(512)
453
486
  @store[key] = p = @store.new(Person)
454
487
  p.name = value
455
488
  ref[key] = value
456
489
  when 1
457
490
  # Add 'B' person
458
- value = 'B' * rand(128)
491
+ value = key + 'B' * rand(32)
459
492
  @store[key] = p = @store.new(Person)
460
493
  p.name = value
461
494
  ref[key] = value
462
495
  when 2
463
496
  # Delete a root entry
464
497
  if ref.keys.length > 11
465
- key = ref.keys[(ref.keys.length / 11).to_i]
498
+ key = ref.keys[rand(ref.keys.length)]
466
499
  expect(@store[key]).not_to be_nil
467
500
  @store[key] = nil
468
501
  ref.delete(key)
469
502
  deletions_since_last_gc += 1
470
503
  end
471
504
  when 3
505
+ # Update a person entry
506
+ if ref.keys.length > 0
507
+ key = ref.keys[rand(ref.keys.length)]
508
+ expect(@store[key]).not_to be_nil
509
+ value = key + 'C' * rand(996)
510
+ p = @store[key]
511
+ p.name = value
512
+ ref[key] = value
513
+ end
514
+ when 4
472
515
  # Call garbage collector
473
516
  if rand(60) == 0
474
517
  @store.gc
@@ -478,32 +521,32 @@ describe PEROBS::Store do
478
521
  deletions_since_last_gc = 0
479
522
  expect(@store.gc).to eq(deletions_since_last_gc)
480
523
  end
481
- when 4
524
+ when 5
482
525
  # Sync store and reload
483
526
  if rand(15) == 0
484
527
  @store.exit
485
528
  @store = PEROBS::Store.new(@db_file, options)
486
529
  end
487
- when 5
530
+ when 6
488
531
  # Replace an entry with 'C' person
489
532
  if ref.keys.length > 13
490
533
  key = ref.keys[(ref.keys.length / 13).to_i]
491
- value = 'C' * rand(1024)
534
+ value = key + 'D' * rand(1024)
492
535
  @store[key] = p = @store.new(Person)
493
536
  p.name = value
494
537
  ref[key] = value
495
538
  deletions_since_last_gc += 1
496
539
  end
497
- when 6
540
+ when 7
498
541
  # Sync and check store
499
542
  if rand(50) == 0
500
- @store.sync
543
+ #@store.sync
501
544
  expect(@store.check(false)).to eq(0)
502
545
  end
503
- when 7
546
+ when 8
504
547
  # Compare a random entry with reference entry
505
548
  if ref.keys.length > 0
506
- key = ref.keys[rand(ref.keys.length - 1)]
549
+ key = ref.keys[rand(ref.keys.length)]
507
550
  expect(@store[key].name).to eq(ref[key])
508
551
  end
509
552
  end