sesame-cli 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/VERSION +1 -1
- data/lib/sesame/cave.rb +7 -8
- data/lib/sesame/jinn.rb +30 -29
- data/sesame-cli.gemspec +3 -3
- data/spec/cave_spec.rb +309 -0
- data/spec/jinn_spec.rb +35 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f22b05a9ccfb4ed20090fe15a4688435773a2fc75dc45c6360f184806a1e0b7
|
4
|
+
data.tar.gz: 02ff7c0924ce62da164a8b2243292d6fa2db0c5c729d0eb48840956de7854467
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 710f4c9022e30461b894edb497d956a0be95e0235756b3e27ffb0921efc7e744fb2edc607987b5b887d25bbf39152eec6a064b6b420a0fdb3b28c9fdcc5ef327
|
7
|
+
data.tar.gz: cd10c77c1879a964ab3998b22e705efd63663127629d93505d713fe86f89a37670950b99f7908bfbf05fcbd28e1fee7c490a067cfb38b5705ff111f90374c27e
|
data/README.md
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
data/lib/sesame/cave.rb
CHANGED
@@ -121,6 +121,7 @@ module Sesame
|
|
121
121
|
@item = nil
|
122
122
|
@store = nil
|
123
123
|
@secret = nil
|
124
|
+
@dirty = false
|
124
125
|
end
|
125
126
|
|
126
127
|
# Lock the cave by encrypting and saving the secret to a lock file, and then
|
@@ -212,11 +213,11 @@ module Sesame
|
|
212
213
|
# True if a particular service has exactly one username.
|
213
214
|
def unique?(service)
|
214
215
|
raise Fail, 'Cannot test service uniqueness; store not open' unless open?
|
215
|
-
|
216
|
+
raise Fail, 'No such service' if @store[service].nil?
|
216
217
|
@store[service].count < 2
|
217
218
|
end
|
218
219
|
|
219
|
-
# Generate and return the
|
220
|
+
# Generate and return the passphrase for a service and username.
|
220
221
|
def get(service, user = nil, index = nil)
|
221
222
|
raise Fail, 'Cannot get service details; store not open' unless open?
|
222
223
|
raise Fail, 'Cannot get the sesame service' if service.casecmp('sesame').zero?
|
@@ -233,8 +234,7 @@ module Sesame
|
|
233
234
|
end
|
234
235
|
raise Fail, 'Service cannot be empty' if service.strip.length.zero?
|
235
236
|
raise Fail, 'User cannot be empty' if user.nil? || user.strip.length.zero?
|
236
|
-
|
237
|
-
raise Fail, 'Service and/or user already exists' unless item.nil?
|
237
|
+
raise Fail, 'User already exists for that service' unless @store[service].nil? || @store[service][user].nil?
|
238
238
|
@store[service] ||= {}
|
239
239
|
@store[service][user] = index || 0
|
240
240
|
@dirty = true
|
@@ -248,7 +248,6 @@ module Sesame
|
|
248
248
|
def update(service, user = nil, index = nil)
|
249
249
|
raise Fail, 'Cannot update service details; store not open' unless open?
|
250
250
|
item = _find(service, user)
|
251
|
-
raise Fail, 'Unable to find that service and/or user' if item.nil?
|
252
251
|
index = item[:index] + 1 if index.nil?
|
253
252
|
index = 0 if index.negative?
|
254
253
|
user = item[:user]
|
@@ -263,7 +262,6 @@ module Sesame
|
|
263
262
|
raise Fail, 'Cannot delete service details; store not open' unless open?
|
264
263
|
raise Fail, 'Cannot delete the sesame service' if service.casecmp('sesame').zero?
|
265
264
|
item = _find(service, user)
|
266
|
-
raise Fail, 'Unable to find that service and/or user' if item.nil?
|
267
265
|
user = item[:user]
|
268
266
|
@store[service].delete(user)
|
269
267
|
@store.delete(service) if @store[service].count.zero?
|
@@ -284,9 +282,10 @@ module Sesame
|
|
284
282
|
end
|
285
283
|
|
286
284
|
def _find(service, user)
|
287
|
-
|
285
|
+
raise Fail, 'No such service' if service.nil? || @store[service].nil?
|
288
286
|
@item =
|
289
287
|
if user.nil?
|
288
|
+
raise Fail, 'No unique user for service' unless unique?(service)
|
290
289
|
item = @store[service].first
|
291
290
|
{
|
292
291
|
service: service,
|
@@ -294,7 +293,7 @@ module Sesame
|
|
294
293
|
index: item.last
|
295
294
|
}
|
296
295
|
elsif @store[service][user].nil?
|
297
|
-
|
296
|
+
raise Fail, 'No such service or user'
|
298
297
|
else
|
299
298
|
index = @store[service][user]
|
300
299
|
{
|
data/lib/sesame/jinn.rb
CHANGED
@@ -7,39 +7,40 @@ require 'clipboard'
|
|
7
7
|
module Sesame
|
8
8
|
# The Jinn class is wholly responsible for interacting with the terminal.
|
9
9
|
class Jinn
|
10
|
-
# Pass in parsed command-line options as a Slop instance.
|
11
|
-
|
10
|
+
# Pass in parsed command-line options as a Slop instance. The optional pow
|
11
|
+
# parameter should only be used to speed up tests.
|
12
|
+
def initialize(opts, pow = 30)
|
12
13
|
I18n.load_path = Dir[File.join(File.dirname(__FILE__), 'lang', '*yml')]
|
13
14
|
@opts = opts
|
14
15
|
_config
|
15
16
|
_parse
|
16
17
|
_welcome
|
17
|
-
@
|
18
|
+
@cave = Cave.new(@opts[:path], pow)
|
18
19
|
rescue Fail => e
|
19
20
|
_error(e.message)
|
20
21
|
end
|
21
22
|
|
22
23
|
# Process the users request, possibly starting an interactive session.
|
23
24
|
def process!
|
24
|
-
return if @
|
25
|
+
return if @cave.nil?
|
25
26
|
@was_locked = false
|
26
27
|
raise Fail, 'Cannot lock and expunge simultaneously' if @opts.lock? && @opts.expunge?
|
27
|
-
if @
|
28
|
+
if @cave.exists?
|
28
29
|
raise Fail, 'Please remove the cave before attempting to reconstruct' if @opts.reconstruct?
|
29
|
-
raise Fail, 'Cannot expunge lock; it doesn\'t exist' if @opts.expunge? && !@
|
30
|
+
raise Fail, 'Cannot expunge lock; it doesn\'t exist' if @opts.expunge? && !@cave.locked?
|
30
31
|
raise Fail, 'Please specify a command (or use interactive mode)' if !@opts.interactive? && @opts[:command].nil? && !@opts.lock? && !@opts.expunge?
|
31
|
-
if @
|
32
|
-
@
|
32
|
+
if @cave.locked? && @opts.expunge?
|
33
|
+
@cave.forget
|
33
34
|
_warn('Lock expunged')
|
34
35
|
end
|
35
|
-
if @
|
36
|
+
if @cave.locked?
|
36
37
|
_unlock
|
37
38
|
@was_locked = true
|
38
39
|
else
|
39
40
|
_open
|
40
41
|
end
|
41
42
|
else
|
42
|
-
@
|
43
|
+
@cave.forget if @cave.locked?
|
43
44
|
_new
|
44
45
|
end
|
45
46
|
_process(@opts[:command])
|
@@ -49,12 +50,12 @@ module Sesame
|
|
49
50
|
break if _prompt
|
50
51
|
end
|
51
52
|
if @opts.expunge?
|
52
|
-
@
|
53
|
+
@cave.close
|
53
54
|
else
|
54
55
|
_lock
|
55
56
|
end
|
56
57
|
elsif @opts.expunge? || (!@was_locked && !@opts.lock?)
|
57
|
-
@
|
58
|
+
@cave.close
|
58
59
|
else
|
59
60
|
_lock
|
60
61
|
end
|
@@ -203,7 +204,7 @@ module Sesame
|
|
203
204
|
_info('reconstruct')
|
204
205
|
words = ask('🔑 ') { |q| q.echo = '*' }
|
205
206
|
end
|
206
|
-
phrase = @
|
207
|
+
phrase = @cave.create!(words)
|
207
208
|
if words.nil?
|
208
209
|
_info('new')
|
209
210
|
_show(phrase)
|
@@ -215,26 +216,26 @@ module Sesame
|
|
215
216
|
def _open
|
216
217
|
_info('open')
|
217
218
|
words = ask('🔑 ') { |q| q.echo = '*' }
|
218
|
-
@
|
219
|
-
_info('path', path: @
|
219
|
+
@cave.open(words)
|
220
|
+
_info('path', path: @cave.path)
|
220
221
|
end
|
221
222
|
|
222
223
|
def _unlock
|
223
224
|
_info('unlock')
|
224
225
|
key = ask('🔑 ') { |q| q.echo = '*' }
|
225
|
-
@
|
226
|
-
_info('path', path: @
|
226
|
+
@cave.unlock(key)
|
227
|
+
_info('path', path: @cave.path)
|
227
228
|
end
|
228
229
|
|
229
230
|
def _forget
|
230
231
|
_info('forgot')
|
231
|
-
@
|
232
|
+
@cave.forget
|
232
233
|
end
|
233
234
|
|
234
235
|
def _list
|
235
236
|
_info('list')
|
236
237
|
if @opts[:service].nil? || @opts[:service].length.zero?
|
237
|
-
@
|
238
|
+
@cave.index.each do |service, users|
|
238
239
|
next if service == 'sesame'
|
239
240
|
if users.count > 1
|
240
241
|
say("#{service} (#{users.count})")
|
@@ -243,7 +244,7 @@ module Sesame
|
|
243
244
|
end
|
244
245
|
end
|
245
246
|
else
|
246
|
-
users = @
|
247
|
+
users = @cave.index[@opts[:service]]
|
247
248
|
raise Fail, 'No such service found, you must be thinking of some other cave' if users.nil? || @opts[:service] == 'sesame'
|
248
249
|
users.sort.each do |user, _|
|
249
250
|
say(user)
|
@@ -252,37 +253,37 @@ module Sesame
|
|
252
253
|
end
|
253
254
|
|
254
255
|
def _get
|
255
|
-
phrase = @
|
256
|
-
_info('get', @
|
256
|
+
phrase = @cave.get(*_question, @opts[:offset])
|
257
|
+
_info('get', @cave.item)
|
257
258
|
_show(phrase)
|
258
259
|
end
|
259
260
|
|
260
261
|
def _add
|
261
|
-
phrase = @
|
262
|
-
_info('add', @
|
262
|
+
phrase = @cave.insert(*_question(true), @opts[:offset])
|
263
|
+
_info('add', @cave.item)
|
263
264
|
_show(phrase)
|
264
265
|
end
|
265
266
|
|
266
267
|
def _next
|
267
|
-
phrase = @
|
268
|
+
phrase = @cave.update(*_question, @opts[:offset])
|
268
269
|
if phrase.nil?
|
269
270
|
_info('next_key')
|
270
271
|
@was_locked = false
|
271
272
|
_set_opt(:lock, true)
|
272
273
|
else
|
273
|
-
_info('next', @
|
274
|
+
_info('next', @cave.item)
|
274
275
|
_show(phrase)
|
275
276
|
end
|
276
277
|
end
|
277
278
|
|
278
279
|
def _delete
|
279
|
-
phrase = @
|
280
|
+
phrase = @cave.delete(*_question)
|
280
281
|
_info('delete')
|
281
282
|
_show(phrase)
|
282
283
|
end
|
283
284
|
|
284
285
|
def _lock
|
285
|
-
key = @
|
286
|
+
key = @cave.lock
|
286
287
|
return if @was_locked
|
287
288
|
_info('lock')
|
288
289
|
_show(key)
|
@@ -348,7 +349,7 @@ module Sesame
|
|
348
349
|
_info('service')
|
349
350
|
service = ask('🏷 ')
|
350
351
|
end
|
351
|
-
if user.nil? && (user_required || !@
|
352
|
+
if user.nil? && (user_required || !@cave.unique?(service))
|
352
353
|
_info('user')
|
353
354
|
user = ask('👤 ')
|
354
355
|
end
|
data/sesame-cli.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: sesame-cli 0.
|
5
|
+
# stub: sesame-cli 1.0.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "sesame-cli".freeze
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "1.0.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Jason Hutchens".freeze, "Jack Casey".freeze]
|
14
|
-
s.date = "2018-04-
|
14
|
+
s.date = "2018-04-25"
|
15
15
|
s.description = "\u{1F9DE} - \"Sesame is a simple password manager for the command-line!\"".freeze
|
16
16
|
s.email = "jasonhutchens@gmail.com".freeze
|
17
17
|
s.executables = ["sesame".freeze]
|
data/spec/cave_spec.rb
CHANGED
@@ -4,11 +4,15 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
4
4
|
|
5
5
|
describe Sesame::Cave do
|
6
6
|
let(:cave) { Sesame::Cave.new(Dir.tmpdir, 20) }
|
7
|
+
let(:deep_cave) { Sesame::Cave.new(Dir.tmpdir) }
|
7
8
|
|
8
9
|
after do
|
9
10
|
cave.close if cave.open?
|
10
11
|
cave.forget if cave.locked?
|
11
12
|
File.delete(cave.path) if cave.exists?
|
13
|
+
deep_cave.close if deep_cave.open?
|
14
|
+
deep_cave.forget if deep_cave.locked?
|
15
|
+
File.delete(deep_cave.path) if deep_cave.exists?
|
12
16
|
end
|
13
17
|
|
14
18
|
describe '#path' do
|
@@ -145,44 +149,349 @@ describe Sesame::Cave do
|
|
145
149
|
end
|
146
150
|
|
147
151
|
describe '#open?' do
|
152
|
+
context 'by default' do
|
153
|
+
it 'returns false' do
|
154
|
+
expect(cave.open?).to be false
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'after #create!' do
|
159
|
+
before do
|
160
|
+
cave.create!
|
161
|
+
end
|
162
|
+
it 'returns true' do
|
163
|
+
expect(cave.open?).to be true
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'after #create! and #close' do
|
168
|
+
before do
|
169
|
+
cave.create!
|
170
|
+
cave.close
|
171
|
+
end
|
172
|
+
it 'returns false' do
|
173
|
+
expect(cave.open?).to be false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'after #create! and #lock' do
|
178
|
+
before do
|
179
|
+
cave.create!
|
180
|
+
cave.lock
|
181
|
+
end
|
182
|
+
it 'returns false' do
|
183
|
+
expect(cave.open?).to be false
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'after @create! and #close and #open' do
|
188
|
+
before do
|
189
|
+
phrase = cave.create!
|
190
|
+
cave.insert('foo', 'bar')
|
191
|
+
cave.close
|
192
|
+
cave.open(phrase)
|
193
|
+
end
|
194
|
+
it 'returns true' do
|
195
|
+
expect(cave.open?).to be true
|
196
|
+
end
|
197
|
+
end
|
148
198
|
end
|
149
199
|
|
150
200
|
describe '#dirty?' do
|
201
|
+
context 'by default' do
|
202
|
+
it 'returns false' do
|
203
|
+
expect(cave.dirty?).to be false
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context 'after #create!' do
|
208
|
+
before do
|
209
|
+
cave.create!
|
210
|
+
end
|
211
|
+
it 'returns true' do
|
212
|
+
expect(cave.dirty?).to be true
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context 'after #create! and #close' do
|
217
|
+
before do
|
218
|
+
cave.create!
|
219
|
+
cave.close
|
220
|
+
end
|
221
|
+
it 'returns false' do
|
222
|
+
expect(cave.dirty?).to be false
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
context 'after #create! and #lock' do
|
227
|
+
before do
|
228
|
+
cave.create!
|
229
|
+
cave.lock
|
230
|
+
end
|
231
|
+
it 'returns false' do
|
232
|
+
expect(cave.dirty?).to be false
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context 'after @create! and #close and #open' do
|
237
|
+
before do
|
238
|
+
phrase = cave.create!
|
239
|
+
cave.insert('foo', 'bar')
|
240
|
+
cave.close
|
241
|
+
cave.open(phrase)
|
242
|
+
end
|
243
|
+
it 'returns false' do
|
244
|
+
expect(cave.dirty?).to be false
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
context 'after #open and #insert' do
|
249
|
+
before do
|
250
|
+
phrase = cave.create!
|
251
|
+
cave.insert('foo', 'bar')
|
252
|
+
cave.close
|
253
|
+
cave.open(phrase)
|
254
|
+
cave.insert('bar', 'foo')
|
255
|
+
end
|
256
|
+
it 'returns true' do
|
257
|
+
expect(cave.dirty?).to be true
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context 'after #open and #update' do
|
262
|
+
before do
|
263
|
+
phrase = cave.create!
|
264
|
+
cave.insert('foo', 'bar')
|
265
|
+
cave.close
|
266
|
+
cave.open(phrase)
|
267
|
+
cave.update('foo', 'bar')
|
268
|
+
end
|
269
|
+
it 'returns true' do
|
270
|
+
expect(cave.dirty?).to be true
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
context 'after #open and #delete' do
|
275
|
+
before do
|
276
|
+
phrase = cave.create!
|
277
|
+
cave.insert('foo', 'bar')
|
278
|
+
cave.close
|
279
|
+
cave.open(phrase)
|
280
|
+
cave.delete('foo', 'bar')
|
281
|
+
end
|
282
|
+
it 'returns true' do
|
283
|
+
expect(cave.dirty?).to be true
|
284
|
+
end
|
285
|
+
end
|
151
286
|
end
|
152
287
|
|
153
288
|
describe '#create!' do
|
289
|
+
context 'by default' do
|
290
|
+
before do
|
291
|
+
cave.create!
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'creates a new cave' do
|
295
|
+
expect(cave.exists?).to be false
|
296
|
+
expect(cave.locked?).to be false
|
297
|
+
expect(cave.open?).to be true
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
context 'with a pass phrase' do
|
302
|
+
before do
|
303
|
+
deep_cave.create!('mammal glue wage paper store detail weave date')
|
304
|
+
deep_cave.insert('twitter', 'kranzky')
|
305
|
+
end
|
306
|
+
|
307
|
+
it 'reconstructs an old cave' do
|
308
|
+
expect(deep_cave.exists?).to be false
|
309
|
+
expect(deep_cave.locked?).to be false
|
310
|
+
expect(deep_cave.open?).to be true
|
311
|
+
expect(deep_cave.get('twitter')).to eq('nylon sand slice party')
|
312
|
+
end
|
313
|
+
end
|
154
314
|
end
|
155
315
|
|
156
316
|
describe '#open' do
|
317
|
+
before do
|
318
|
+
phrase = cave.create!
|
319
|
+
cave.insert('foo', 'bar')
|
320
|
+
cave.close
|
321
|
+
cave.open(phrase)
|
322
|
+
cave.get('foo')
|
323
|
+
end
|
324
|
+
it 'opens an existing cave' do
|
325
|
+
expect(cave.exists?).to be true
|
326
|
+
expect(cave.locked?).to be false
|
327
|
+
expect(cave.open?).to be true
|
328
|
+
expect(cave.item[:user]).to eq('bar')
|
329
|
+
end
|
157
330
|
end
|
158
331
|
|
159
332
|
describe '#close' do
|
333
|
+
before do
|
334
|
+
cave.create!
|
335
|
+
cave.insert('foo', 'bar')
|
336
|
+
cave.close
|
337
|
+
end
|
338
|
+
it 'closes a cave' do
|
339
|
+
expect(cave.exists?).to be true
|
340
|
+
expect(cave.locked?).to be false
|
341
|
+
expect(cave.open?).to be false
|
342
|
+
end
|
160
343
|
end
|
161
344
|
|
162
345
|
describe '#lock' do
|
346
|
+
before do
|
347
|
+
cave.create!
|
348
|
+
cave.insert('foo', 'bar')
|
349
|
+
cave.lock
|
350
|
+
end
|
351
|
+
it 'locks a cave' do
|
352
|
+
expect(cave.exists?).to be true
|
353
|
+
expect(cave.locked?).to be true
|
354
|
+
expect(cave.open?).to be false
|
355
|
+
end
|
163
356
|
end
|
164
357
|
|
165
358
|
describe '#unlock' do
|
359
|
+
context 'with a word phrase' do
|
360
|
+
before do
|
361
|
+
cave.create!
|
362
|
+
cave.insert('foo', 'bar')
|
363
|
+
phrase = cave.lock
|
364
|
+
cave.unlock(phrase)
|
365
|
+
cave.get('foo')
|
366
|
+
end
|
367
|
+
it 'unlocks a cave' do
|
368
|
+
expect(cave.exists?).to be true
|
369
|
+
expect(cave.locked?).to be false
|
370
|
+
expect(cave.open?).to be true
|
371
|
+
expect(cave.item[:user]).to eq('bar')
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
context 'with a character code' do
|
376
|
+
before do
|
377
|
+
cave.create!
|
378
|
+
cave.insert('foo', 'bar')
|
379
|
+
code = cave.lock.split(' ').map { |w| w[0] }.join
|
380
|
+
cave.unlock(code)
|
381
|
+
cave.get('foo')
|
382
|
+
end
|
383
|
+
it 'unlocks a cave' do
|
384
|
+
expect(cave.exists?).to be true
|
385
|
+
expect(cave.locked?).to be false
|
386
|
+
expect(cave.open?).to be true
|
387
|
+
expect(cave.item[:user]).to eq('bar')
|
388
|
+
end
|
389
|
+
end
|
166
390
|
end
|
167
391
|
|
168
392
|
describe '#forget' do
|
393
|
+
before do
|
394
|
+
cave.create!
|
395
|
+
cave.insert('foo', 'bar')
|
396
|
+
cave.lock
|
397
|
+
cave.forget
|
398
|
+
end
|
399
|
+
it 'removes the lock file' do
|
400
|
+
expect(cave.exists?).to be true
|
401
|
+
expect(cave.locked?).to be false
|
402
|
+
expect(cave.open?).to be false
|
403
|
+
end
|
169
404
|
end
|
170
405
|
|
171
406
|
describe '#index' do
|
407
|
+
before do
|
408
|
+
cave.create!
|
409
|
+
cave.insert('foo', 'bar')
|
410
|
+
cave.insert('foo', 'xxx')
|
411
|
+
cave.insert('bar', 'foo')
|
412
|
+
end
|
413
|
+
let(:index) { cave.index }
|
414
|
+
it 'returns the contents of the cave' do
|
415
|
+
expect(index.count).to eq(3)
|
416
|
+
expect(index.keys[0]).to eq('bar')
|
417
|
+
expect(index.keys[2]).to eq('sesame')
|
418
|
+
expect(index['foo'].count).to eq(2)
|
419
|
+
expect(index['foo']['xxx']).to eq(0)
|
420
|
+
end
|
172
421
|
end
|
173
422
|
|
174
423
|
describe '#unique?' do
|
424
|
+
before do
|
425
|
+
cave.create!
|
426
|
+
cave.insert('foo', 'bar')
|
427
|
+
cave.insert('foo', 'xxx')
|
428
|
+
cave.insert('bar', 'foo')
|
429
|
+
end
|
430
|
+
it 'returns true for services that contain exactly one user' do
|
431
|
+
expect(cave.unique?('foo')).to be false
|
432
|
+
expect(cave.unique?('bar')).to be true
|
433
|
+
expect { cave.unique?('xxx') }.to raise_error(Sesame::Fail)
|
434
|
+
end
|
175
435
|
end
|
176
436
|
|
177
437
|
describe '#get' do
|
438
|
+
before do
|
439
|
+
cave.create!
|
440
|
+
cave.insert('foo', 'bar')
|
441
|
+
cave.insert('foo', 'xxx')
|
442
|
+
end
|
443
|
+
let!(:phrase) { cave.insert('bar', 'foo') }
|
444
|
+
it 'returns the phrase' do
|
445
|
+
expect(cave.item[:index]).to eq(0)
|
446
|
+
expect(cave.get('bar')).to eq(phrase)
|
447
|
+
expect(cave.get('bar', 'foo')).to eq(phrase)
|
448
|
+
expect { cave.get('foo') }.to raise_error(Sesame::Fail)
|
449
|
+
expect { cave.get('xxx') }.to raise_error(Sesame::Fail)
|
450
|
+
expect(cave.get('foo', 'xxx').split(' ').count).to eq(4)
|
451
|
+
end
|
178
452
|
end
|
179
453
|
|
180
454
|
describe '#insert' do
|
455
|
+
before do
|
456
|
+
cave.create!
|
457
|
+
cave.insert('foo', 'bar')
|
458
|
+
end
|
459
|
+
it 'inserts the item' do
|
460
|
+
expect(cave.item[:service]).to eq('foo')
|
461
|
+
expect(cave.item[:user]).to eq('bar')
|
462
|
+
expect(cave.item[:index]).to eq(0)
|
463
|
+
expect { cave.insert('foo', 'bar') }.to raise_error(Sesame::Fail)
|
464
|
+
expect(cave.insert('foo', 'xxx').split(' ').count).to eq(4)
|
465
|
+
expect(cave.item[:user]).to eq('xxx')
|
466
|
+
end
|
181
467
|
end
|
182
468
|
|
183
469
|
describe '#update' do
|
470
|
+
before do
|
471
|
+
cave.create!
|
472
|
+
end
|
473
|
+
let!(:phrase) { cave.insert('foo', 'bar') }
|
474
|
+
it 'updates the item' do
|
475
|
+
expect(cave.item[:index]).to eq(0)
|
476
|
+
expect(cave.get('foo')).to eq(phrase)
|
477
|
+
expect(cave.update('foo')).not_to eq(phrase)
|
478
|
+
expect(cave.item[:index]).to eq(1)
|
479
|
+
expect(cave.get('foo')).not_to eq(phrase)
|
480
|
+
end
|
184
481
|
end
|
185
482
|
|
186
483
|
describe '#delete' do
|
484
|
+
before do
|
485
|
+
cave.create!
|
486
|
+
cave.insert('foo', 'bar')
|
487
|
+
end
|
488
|
+
let!(:phrase) { cave.insert('bar', 'foo') }
|
489
|
+
it 'deletes the item' do
|
490
|
+
expect(cave.get('bar')).to eq(phrase)
|
491
|
+
expect(cave.delete('bar')).to eq(phrase)
|
492
|
+
expect { cave.get('bar') }.to raise_error(Sesame::Fail)
|
493
|
+
expect(cave.item[:service]).to eq('bar')
|
494
|
+
expect { cave.get('xxx') }.to raise_error(Sesame::Fail)
|
495
|
+
end
|
187
496
|
end
|
188
497
|
end
|
data/spec/jinn_spec.rb
CHANGED
@@ -3,5 +3,39 @@
|
|
3
3
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
4
4
|
|
5
5
|
describe Sesame::Jinn do
|
6
|
-
let(:
|
6
|
+
let(:opts) { double('opts') }
|
7
|
+
let(:jinn) { Sesame::Jinn.new(opts, 20) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
option = double('option')
|
11
|
+
allow(opts).to receive(:echo?) { true }
|
12
|
+
allow(opts).to receive(:interactive?) { false }
|
13
|
+
allow(opts).to receive(:quiet?) { true }
|
14
|
+
allow(opts).to receive(:list?) { false }
|
15
|
+
allow(opts).to receive(:add?) { false }
|
16
|
+
allow(opts).to receive(:get?) { false }
|
17
|
+
allow(opts).to receive(:next?) { false }
|
18
|
+
allow(opts).to receive(:delete?) { false }
|
19
|
+
allow(opts).to receive(:lock?) { false }
|
20
|
+
allow(opts).to receive(:expunge?) { false }
|
21
|
+
allow(opts).to receive(:reconstruct?) { false }
|
22
|
+
allow(opts).to receive(:[]) { '/tmp' }
|
23
|
+
allow(opts).to receive(:option) { option }
|
24
|
+
allow(option).to receive(:ensure_call)
|
25
|
+
end
|
26
|
+
|
27
|
+
after do
|
28
|
+
cave = jinn.instance_variable_get(:@cave)
|
29
|
+
cave.close if cave.open?
|
30
|
+
cave.forget if cave.locked?
|
31
|
+
File.delete(cave.path) if cave.exists?
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#process!' do
|
35
|
+
context 'no arguments supplied' do
|
36
|
+
it 'exits with an error message' do
|
37
|
+
jinn.process!
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
7
41
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sesame-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Hutchens
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-04-
|
12
|
+
date: 2018-04-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bases
|