sesame-cli 0.2.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.
- 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
|