keepassx 0.1.0 → 1.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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +30 -0
  3. data/.gitignore +9 -0
  4. data/.rubocop.yml +64 -0
  5. data/.travis.yml +12 -3
  6. data/Gemfile +4 -2
  7. data/Guardfile +16 -0
  8. data/LICENSE +19 -0
  9. data/README.md +33 -0
  10. data/Rakefile +3 -2
  11. data/keepassx.gemspec +20 -10
  12. data/lib/keepassx.rb +42 -3
  13. data/lib/keepassx/aes_crypt.rb +16 -6
  14. data/lib/keepassx/database.rb +218 -27
  15. data/lib/keepassx/database/dumper.rb +87 -0
  16. data/lib/keepassx/database/finder.rb +102 -0
  17. data/lib/keepassx/database/loader.rb +217 -0
  18. data/lib/keepassx/entry.rb +70 -38
  19. data/lib/keepassx/field/base.rb +191 -0
  20. data/lib/keepassx/field/entry.rb +32 -0
  21. data/lib/keepassx/field/group.rb +27 -0
  22. data/lib/keepassx/fieldable.rb +161 -0
  23. data/lib/keepassx/group.rb +93 -20
  24. data/lib/keepassx/hashable_payload.rb +6 -0
  25. data/lib/keepassx/header.rb +102 -27
  26. data/lib/keepassx/version.rb +5 -0
  27. data/spec/factories.rb +23 -0
  28. data/spec/fixtures/database_empty.kdb +0 -0
  29. data/spec/fixtures/database_test.kdb +0 -0
  30. data/spec/fixtures/database_test_dumped.yml +76 -0
  31. data/spec/fixtures/database_with_key.kdb +0 -0
  32. data/spec/fixtures/database_with_key.key +1 -0
  33. data/spec/fixtures/database_with_key2.key +1 -0
  34. data/spec/fixtures/test_data_array.yml +113 -0
  35. data/spec/fixtures/test_data_array_dumped.yml +124 -0
  36. data/spec/keepassx/database_spec.rb +491 -29
  37. data/spec/keepassx/entry_spec.rb +95 -0
  38. data/spec/keepassx/group_spec.rb +92 -0
  39. data/spec/keepassx_spec.rb +17 -0
  40. data/spec/spec_helper.rb +59 -3
  41. metadata +143 -69
  42. data/.rvmrc +0 -1
  43. data/Gemfile.lock +0 -28
  44. data/lib/keepassx/entry_field.rb +0 -49
  45. data/lib/keepassx/group_field.rb +0 -44
  46. data/spec/test_database.kdb +0 -0
@@ -1,56 +1,518 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Keepassx::Database do
4
- describe 'self.open' do
5
- it "creates a new instance of the databse with the file" do
6
- db = Keepassx::Database.open(TEST_DATABASE_PATH)
7
- db.should_not be_nil
4
+
5
+ GROUPS_COUNT = 5
6
+ ENTRIES_COUNT = 5
7
+
8
+ let(:data_array) { YAML.load(File.read(File.join(FIXTURE_PATH, 'test_data_array.yml'))) }
9
+ let(:data_array_dumped) { File.read(File.join(FIXTURE_PATH, 'test_data_array_dumped.yml')) }
10
+
11
+ let(:test_db) { Keepassx::Database.new(TEST_DATABASE_PATH) }
12
+ let(:test_db_dumped) { File.read(File.join(FIXTURE_PATH, 'database_test_dumped.yml')) }
13
+
14
+ let(:empty_db) { Keepassx::Database.new(EMPTY_DATABASE_PATH) }
15
+ let(:test_group) { build(:group) }
16
+ let(:test_entry) { build(:entry) }
17
+
18
+ let(:keyfile_db) { Keepassx::Database.new(KEYFILE_DATABASE_PATH) }
19
+ let(:keyfile) { File.join(FIXTURE_PATH, 'database_with_key.key') }
20
+ let(:keyfile2) { File.join(FIXTURE_PATH, 'database_with_key2.key') }
21
+
22
+ describe 'empty database' do
23
+ before :each do
24
+ empty_db.unlock('test')
25
+ end
26
+
27
+ it 'should have 2 groups' do
28
+ expect(empty_db.groups.size).to eq 2
29
+ expect(empty_db.groups.map(&:name).sort).to eq ['Internet', 'eMail']
30
+ end
31
+
32
+ it 'should have 2 special entries' do
33
+ expect(empty_db.entries.size).to eq 2
34
+ expect(empty_db.entries.map(&:name).sort).to eq ['Meta-Info', 'Meta-Info']
35
+ end
36
+
37
+ it 'should have 1 KPX_CUSTOM_ICONS_4 entry' do
38
+ entry = empty_db.find_entry(notes: 'KPX_CUSTOM_ICONS_4')
39
+ expect(entry).to be_a(Keepassx::Entry)
40
+ expect(entry.notes).to eq 'KPX_CUSTOM_ICONS_4'
41
+ end
42
+
43
+ it 'should have 1 KPX_GROUP_TREE_STATE entry' do
44
+ entry = empty_db.find_entry(notes: 'KPX_GROUP_TREE_STATE')
45
+ expect(entry).to be_a(Keepassx::Entry)
46
+ expect(entry.notes).to eq 'KPX_GROUP_TREE_STATE'
8
47
  end
9
48
  end
10
49
 
11
- describe "unlock" do
12
- before :each do
13
- @db = Keepassx::Database.open(TEST_DATABASE_PATH)
14
- @db.should be_valid
50
+
51
+ describe '.new' do
52
+ context 'when database is instanciated from file' do
53
+ let(:test_db) { described_class.new(File.open(TEST_DATABASE_PATH)) }
54
+
55
+ before :each do
56
+ test_db.unlock('testmasterpassword')
57
+ end
58
+
59
+ it 'properly initialized from file' do
60
+ expect { test_db }.to_not raise_error
61
+ end
62
+
63
+ it 'should have valid headers' do
64
+ expect(test_db.valid?).to be true
65
+ end
66
+
67
+ it 'should have valid length' do
68
+ expect(test_db.length).to eq 1457
69
+ end
70
+
71
+ it 'should have valid encryption_type headers' do
72
+ expect(test_db.header.encryption_type).to eq 'SHA2'
73
+ end
74
+
75
+ it 'has groups_count counter properly set' do
76
+ expect(test_db.header.groups_count).to eq GROUPS_COUNT
77
+ end
78
+
79
+ it 'has entries_count counter properly set' do
80
+ expect(test_db.header.entries_count).to eq ENTRIES_COUNT
81
+ end
82
+
83
+ it 'contains proper number of test groups' do
84
+ expect(test_db.groups.length).to eq GROUPS_COUNT
85
+ end
86
+
87
+ it 'contains proper number of test entries' do
88
+ expect(test_db.entries.length).to eq ENTRIES_COUNT
89
+ end
90
+
91
+ it 'preserves original data' do
92
+ expect(test_db.to_yaml(skip_date: true)).to eq test_db_dumped
93
+ end
15
94
  end
16
95
 
17
- it "returns true when the master password is correct" do
18
- @db.unlock('testmasterpassword').should be_true
96
+ context 'when database is instanciated from string' do
97
+ let(:test_db) { described_class.new(TEST_DATABASE_PATH) }
98
+
99
+ before :each do
100
+ test_db.unlock('testmasterpassword')
101
+ end
102
+
103
+ it 'properly initialized from string' do
104
+ expect { test_db }.to_not raise_error
105
+ end
106
+
107
+ it 'should have valid headers' do
108
+ expect(test_db.valid?).to be true
109
+ end
110
+
111
+ it 'should have valid length' do
112
+ expect(test_db.length).to eq 1457
113
+ end
114
+
115
+ it 'should have valid encryption_type headers' do
116
+ expect(test_db.header.encryption_type).to eq 'SHA2'
117
+ end
118
+
119
+ it 'has groups_count counter properly set' do
120
+ expect(test_db.header.groups_count).to eq GROUPS_COUNT
121
+ end
122
+
123
+ it 'has entries_count counter properly set' do
124
+ expect(test_db.header.entries_count).to eq ENTRIES_COUNT
125
+ end
126
+
127
+ it 'contains proper number of test groups' do
128
+ expect(test_db.groups.length).to eq GROUPS_COUNT
129
+ end
130
+
131
+ it 'contains proper number of test entries' do
132
+ expect(test_db.entries.length).to eq ENTRIES_COUNT
133
+ end
134
+
135
+ it 'preserves original data' do
136
+ expect(test_db.to_yaml(skip_date: true)).to eq test_db_dumped
137
+ end
19
138
  end
20
139
 
21
- it "returns false when the master password is incorrect" do
22
- @db.unlock('bad password').should be_false
140
+ context 'when database is instanciated from array' do
141
+ let(:test_db) { described_class.new(data_array) }
142
+
143
+ it 'properly initialized from Array' do
144
+ expect { test_db }.to_not raise_error
145
+ end
146
+
147
+ it 'should have valid headers' do
148
+ expect(test_db.valid?).to be true
149
+ end
150
+
151
+ it 'should have valid length' do
152
+ expect(test_db.length).to eq 2189
153
+ end
154
+
155
+ it 'should have valid encryption_type headers' do
156
+ expect(test_db.header.encryption_type).to eq 'SHA2'
157
+ end
158
+
159
+ it 'has groups_count counter properly set' do
160
+ expect(test_db.header.groups_count).to eq 13
161
+ end
162
+
163
+ it 'has entries_count counter properly set' do
164
+ expect(test_db.header.entries_count).to eq 4
165
+ end
166
+
167
+ it 'contains proper number of test groups' do
168
+ expect(test_db.groups.length).to eq 13
169
+ end
170
+
171
+ it 'contains proper number of test entries' do
172
+ expect(test_db.entries.length).to eq 4
173
+ end
174
+
175
+ it 'preserves original data' do
176
+ expect(test_db.to_yaml(skip_date: true)).to eq data_array_dumped
177
+ end
178
+ end
179
+ end
180
+
181
+
182
+ describe '#unlock' do
183
+ context 'when no key file is needed' do
184
+ it 'returns true when the master password is correct' do
185
+ expect(test_db.unlock('testmasterpassword')).to be true
186
+ end
187
+
188
+ it 'returns false when the master password is incorrect' do
189
+ expect(test_db.unlock('bad password')).to be false
190
+ end
191
+ end
192
+
193
+ context 'when a key file is needed' do
194
+ it 'returns true when the master password is correct and a valid keyfile is given' do
195
+ expect(keyfile_db.unlock('test', keyfile)).to be true
196
+ end
197
+
198
+ it 'returns false when the master password is incorrect' do
199
+ expect(keyfile_db.unlock('bad password', keyfile)).to be false
200
+ end
201
+
202
+ it 'returns false when the keyfile is missing' do
203
+ expect(keyfile_db.unlock('test')).to be false
204
+ end
205
+
206
+ it 'returns false when the keyfile dont match' do
207
+ expect(keyfile_db.unlock('test', keyfile2)).to be false
208
+ end
23
209
  end
24
210
  end
25
211
 
26
- describe "an unlocked database" do
212
+
213
+ describe '#locked?' do
214
+ it 'returns true when database is locked' do
215
+ expect(test_db.locked?).to be true
216
+ end
217
+
218
+ it 'returns false when database is unlocked' do
219
+ test_db.unlock('testmasterpassword')
220
+ expect(test_db.locked?).to be false
221
+ end
222
+ end
223
+
224
+
225
+ describe '#to_a' do
226
+ it 'returns Array database representation' do
227
+ expect(described_class.new(data_array).to_a.class).to be Array
228
+ end
229
+ end
230
+
231
+
232
+ describe '#checksum' do
233
+ let(:db1) { described_class.new data_array }
234
+ let(:db2) { described_class.new data_array }
235
+
236
+ it 'has the same checksum for the same data' do
237
+ expect(db1.checksum).to eq db2.checksum
238
+ end
239
+ end
240
+
241
+
242
+ context 'unlocked database' do
27
243
  before :each do
28
- @db = Keepassx::Database.open(TEST_DATABASE_PATH)
29
- @db.unlock('testmasterpassword')
244
+ test_db.unlock('testmasterpassword')
245
+ end
246
+
247
+ describe '#entries' do
248
+ it 'has entries' do
249
+ expect(test_db.entries.map(&:name).sort).to eq ['Meta-Info', 'Meta-Info', 'entry2', 'test entry', 'test entry 2']
250
+ end
251
+ end
252
+
253
+ describe '#groups' do
254
+ it 'has groups' do
255
+ expect(test_db.groups.map(&:name).sort).to eq ['Backup', 'Internet', 'Web', 'Wikipedia', 'eMail']
256
+ end
257
+ end
258
+
259
+ describe '#find_entry' do
260
+ it 'can find entries by their name' do
261
+ expect(test_db.find_entry('test entry').password).to eq 'testpassword'
262
+ expect(test_db.find_entry(name: 'test entry').creation_time).to eq Time.local(2011, 9, 3, 15, 34, 47)
263
+ expect(test_db.find_entry('foo')).to be nil
264
+ end
265
+ end
266
+
267
+ describe '#find_group' do
268
+ it 'can find groups by their name' do
269
+ expect(test_db.find_group('Backup').name).to eq 'Backup'
270
+ expect(test_db.find_group('foo')).to be nil
271
+ end
272
+
273
+ it 'has "Internet" group level properly set' do
274
+ expect(test_db.find_group('Internet').level).to eq 0
275
+ end
276
+
277
+ it 'has "Internet" group parent properly set' do
278
+ expect(test_db.find_group('Internet').parent).to be nil
279
+ end
280
+
281
+ it 'has "Web" group level properly set' do
282
+ expect(test_db.find_group('Web').level).to eq 1
283
+ end
284
+
285
+ it 'has "Web" group parent properly set' do
286
+ expect(test_db.find_group('Web').parent).to eq test_db.find_group('Internet')
287
+ end
288
+
289
+ it 'has "Wikipedia" group level properly set' do
290
+ expect(test_db.find_group('Wikipedia').level).to eq 2
291
+ end
292
+
293
+ it 'has "Wikipedia" group parent properly set' do
294
+ expect(test_db.find_group('Wikipedia').parent).to eq test_db.find_group('Web')
295
+ end
296
+
297
+ it 'has "eMail" group level properly set' do
298
+ expect(test_db.find_group('eMail').level).to eq 0
299
+ end
300
+
301
+ it 'has "eMail" group parent properly set' do
302
+ expect(test_db.find_group('eMail').parent).to be nil
303
+ end
30
304
  end
31
305
 
32
- it "can find entries by their title" do
33
- @db.entry("test entry").password.should == "testpassword"
306
+ describe '#find_entries' do
307
+ it 'should returns a list of entries' do
308
+ expect(test_db.find_entries).to eq test_db.entries
309
+ expect { |b| test_db.find_entries(&b) }.to yield_successive_args(*test_db.entries)
310
+ end
34
311
  end
35
312
 
36
- it "can find groups" do
37
- @db.groups.map(&:name).sort.should == ["Backup", "Internet", "eMail"]
313
+ describe '#find_groups' do
314
+ it 'should returns a list of groups' do
315
+ expect(test_db.find_groups).to eq test_db.groups
316
+ expect { |b| test_db.find_groups(&b) }.to yield_successive_args(*test_db.groups)
317
+ end
38
318
  end
39
319
 
40
- it "can search for entries" do
41
- entries = @db.search "test"
42
- entries.first.title.should == "test entry"
320
+ describe '#search' do
321
+ it 'can search for entries' do
322
+ entries = test_db.search('test')
323
+ expect(entries.first.name).to eq 'test entry'
324
+ end
325
+
326
+ it 'can search for entries case-insensitively' do
327
+ entries = test_db.search('TEST')
328
+ expect(entries.first.name).to eq 'test entry'
329
+ end
330
+
331
+ # it 'will find the current values of entries with history' do
332
+ # entries = test_db.search 'entry2'
333
+ # expect(entries.size).to eq 1
334
+ # expect(entries.first.name).to eq 'entry2'
335
+ # expect(entries.first.backup?).to be true
336
+ # end
43
337
  end
44
338
 
45
- it "can search for entries case-insensitively" do
46
- entries = @db.search "TEST"
47
- entries.first.title.should == "test entry"
339
+ describe '#add_group' do
340
+ context 'when arg is a Keepassx::Group' do
341
+ it 'should increment groups_count' do
342
+ expect(test_db.groups.size).to eq GROUPS_COUNT
343
+ test_db.add_group(test_group)
344
+ expect(test_db.groups.size).to eq GROUPS_COUNT + 1
345
+ expect(test_db.header.groups_count).to eq GROUPS_COUNT + 1
346
+ end
347
+ end
348
+
349
+ context 'when arg is a Hash of options' do
350
+ it 'should increment groups_count' do
351
+ expect(test_db.groups.size).to eq GROUPS_COUNT
352
+ test_db.add_group(attributes_for(:group))
353
+ expect(test_db.groups.size).to eq GROUPS_COUNT + 1
354
+ expect(test_db.header.groups_count).to eq GROUPS_COUNT + 1
355
+ end
356
+ end
357
+
358
+ context 'when arg is neither a Keepassx::Group or a Hash of options' do
359
+ it 'should raise an error' do
360
+ expect { test_db.add_group(nil) }.to raise_error(ArgumentError)
361
+ end
362
+ end
363
+
364
+ context 'with nested groups' do
365
+ it 'should increment groups_count' do
366
+ expect(test_db.groups.size).to eq GROUPS_COUNT
367
+ parent_group = test_db.add_group(attributes_for(:group, id: 0, name: 'parent_group'))
368
+ expect(test_db.groups.size).to eq GROUPS_COUNT + 1
369
+ expect(test_db.groups).to include(parent_group)
370
+ child_group = test_db.add_group(attributes_for(:group, id: 1, name: 'child_group', parent: parent_group))
371
+ expect(test_db.groups.size).to eq GROUPS_COUNT + 2
372
+ expect(test_db.header.groups_count).to eq GROUPS_COUNT + 2
373
+ expect(child_group.parent).to eq parent_group
374
+ end
375
+
376
+ it 'should increment groups_count' do
377
+ expect(test_db.groups.size).to eq GROUPS_COUNT
378
+ parent_group = test_db.add_group(attributes_for(:group, id: 0, name: 'parent_group'))
379
+ expect(test_db.groups.size).to eq GROUPS_COUNT + 1
380
+ expect(test_db.groups).to include(parent_group)
381
+ child_group = test_db.add_group(attributes_for(:group, id: 1, name: 'child_group', parent: :parent_group))
382
+ expect(test_db.groups.size).to eq GROUPS_COUNT + 2
383
+ expect(test_db.header.groups_count).to eq GROUPS_COUNT + 2
384
+ expect(child_group.parent).to eq parent_group
385
+ end
386
+ end
48
387
  end
49
388
 
50
- it "will find the current values of entries with history" do
51
- entries = @db.search "entry2"
52
- entries.size.should == 1
53
- entries.first.title.should == "entry2"
389
+ describe '#add_entry' do
390
+ context 'when arg is a Keepassx::Entry' do
391
+ it 'should increment entries_count' do
392
+ expect(test_db.entries.size).to eq ENTRIES_COUNT
393
+ test_db.add_entry(test_entry)
394
+ expect(test_db.entries.size).to eq ENTRIES_COUNT + 1
395
+ expect(test_db.header.entries_count).to eq ENTRIES_COUNT + 1
396
+ end
397
+ end
398
+
399
+ context 'when arg is a Hash of options' do
400
+ it 'should increment entries_count' do
401
+ expect(test_db.entries.size).to eq ENTRIES_COUNT
402
+ test_db.add_entry(attributes_for(:entry))
403
+ expect(test_db.entries.size).to eq ENTRIES_COUNT + 1
404
+ expect(test_db.header.entries_count).to eq ENTRIES_COUNT + 1
405
+ end
406
+ end
407
+
408
+ context 'when arg is neither a Keepassx::Group or a Hash of options' do
409
+ it 'should raise an error' do
410
+ expect { test_db.add_group(nil) }.to raise_error(ArgumentError)
411
+ end
412
+ end
413
+ end
414
+
415
+ describe '#delete_group' do
416
+ it 'should decrement entries_count' do
417
+ group = test_db.find_group('eMail')
418
+ expect(test_db.groups.size).to eq GROUPS_COUNT
419
+ expect(test_db.header.groups_count).to eq GROUPS_COUNT
420
+ test_db.delete_group(group)
421
+ expect(test_db.groups.size).to eq GROUPS_COUNT - 1
422
+ expect(test_db.header.groups_count).to eq GROUPS_COUNT - 1
423
+ end
424
+ end
425
+
426
+ describe '#delete_entry' do
427
+ it 'should decrement entries_count' do
428
+ entry = test_db.find_entry('test entry')
429
+ expect(test_db.entries.size).to eq ENTRIES_COUNT
430
+ expect(test_db.header.entries_count).to eq ENTRIES_COUNT
431
+ test_db.delete_entry(entry)
432
+ expect(test_db.entries.size).to eq ENTRIES_COUNT - 1
433
+ expect(test_db.header.entries_count).to eq ENTRIES_COUNT - 1
434
+ end
435
+ end
436
+
437
+ describe '#save' do
438
+ context 'when database is saved from an existing file' do
439
+ it 'should save the database in KeePassX format' do
440
+ # Save database in /tmp to not override existing one
441
+ expect { test_db.save(path: '/tmp/keepass1.kdb') }.to_not raise_error
442
+ expect(File.exist?('/tmp/keepass1.kdb')).to be true
443
+
444
+ # Reopen it and compare with original db
445
+ db = described_class.new('/tmp/keepass1.kdb')
446
+ expect(db.locked?).to be true
447
+ db.unlock('testmasterpassword')
448
+ expect(db.to_yaml).to eq test_db.to_yaml
449
+
450
+ # Be sure to delete existing tmp files
451
+ expect(File.unlink('/tmp/keepass1.kdb')).to eq 1
452
+ expect(File.exist?('/tmp/keepass1.kdb')).to be false
453
+ end
454
+ end
455
+
456
+ context 'when database is saved from a data file' do
457
+ it 'should raise an error if path is not set' do
458
+ test_db = described_class.new(data_array)
459
+ expect { test_db.save }.to raise_error(ArgumentError)
460
+ end
461
+
462
+ it 'should raise an error if path is not set' do
463
+ test_db = described_class.new(data_array)
464
+ expect { test_db.save(password: 'foo') }.to raise_error(ArgumentError)
465
+ end
466
+
467
+ it 'should raise an error if password is not set' do
468
+ test_db = described_class.new(data_array)
469
+ expect { test_db.save(path: '/tmp/keepass2.kdb') }.to raise_error(ArgumentError)
470
+ end
471
+
472
+ it 'should save the database if the path and the password are set' do
473
+ # Create new db from array of data
474
+ test_db = described_class.new(data_array)
475
+
476
+ # Save database in /tmp
477
+ expect { test_db.save(path: '/tmp/keepass2.kdb', password: 'testmasterpassword') }.to_not raise_error
478
+ expect(File.exist?('/tmp/keepass2.kdb')).to be true
479
+
480
+ # Reopen it and compare with original db
481
+ db = described_class.new('/tmp/keepass2.kdb')
482
+ expect(db.locked?).to be true
483
+ db.unlock('testmasterpassword')
484
+ expect(db.to_yaml).to eq test_db.to_yaml
485
+
486
+ # Be sure to delete existing tmp files
487
+ expect(File.unlink('/tmp/keepass2.kdb')).to eq 1
488
+ expect(File.exist?('/tmp/keepass2.kdb')).to be false
489
+ end
490
+ end
491
+ end
492
+ end
493
+
494
+
495
+ describe 'create database from scratch' do
496
+ it 'should allow creation of database from scratch' do
497
+ # Create a new Database object
498
+ db = described_class.new('/tmp/test_db.kdb')
499
+ # Add a group
500
+ group = db.add_group(name: 'Foo')
501
+ # Add an entry in this group
502
+ entry = db.add_entry(name: 'Bar', group: group)
503
+ # Save database
504
+ expect { db.save(password: 'testpassword') }.to_not raise_error
505
+ # Do some checks
506
+ expect(File.exist?('/tmp/test_db.kdb')).to be true
507
+
508
+ # Reopen it and compare with original db
509
+ new_db = described_class.new('/tmp/test_db.kdb')
510
+ expect(new_db.locked?).to be true
511
+ new_db.unlock('testpassword')
512
+ expect(new_db.to_yaml(skip_date: true)).to eq db.to_yaml(skip_date: true)
513
+
514
+ # Be sure to delete existing tmp files
515
+ expect(File.unlink('/tmp/test_db.kdb')).to eq 1
54
516
  end
55
517
  end
56
518
  end