keyrack 0.2.0 → 0.2.1

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.
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ - Break up runner tests into smaller pieces
2
+ - Break up cucumber features into smaller pieces
3
+ - Handle multiple usernames for the same site
4
+ - Delete empty groups when last entry is deleted
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.2.1
@@ -11,7 +11,12 @@ Feature: Console runner
11
11
  * I wait a few seconds
12
12
  * the output should contain "Choose storage type:"
13
13
  * I type "filesystem"
14
- * the output should contain "n. Add new"
14
+
15
+ * the output should contain "g. New group"
16
+ * I type "g" to add a new group
17
+ * the output should contain "Group:"
18
+ * I type "Social"
19
+ * the output should contain "n. New entry"
15
20
  * I type "n" to add a new entry
16
21
  * the output should contain "Label:"
17
22
  * I type "Twitter"
@@ -23,9 +28,28 @@ Feature: Console runner
23
28
  * I type "kittens"
24
29
  * the output should contain "Password (again):"
25
30
  * I type "kittens"
26
- * the output should contain "1. Twitter"
31
+ * the output should contain "1. Twitter [dudeguy]"
27
32
  * the output should also contain "s. Save"
28
33
  * I type "s" to save the database
34
+ * the output should contain "t. Top level menu"
35
+ * I type "t"
36
+ * the output should match /1\. .+Social.+/
37
+
38
+ * the output should also contain "n. New entry"
39
+ * I type "n" to add a new entry
40
+ * the output should contain "Label:"
41
+ * I type "Company X"
42
+ * the output should contain "Username:"
43
+ * I type "buddypal"
44
+ * the output should contain "Generate password?"
45
+ * I type "y" for yes
46
+ * the output should contain "Sound good? [yn]"
47
+ * I type "y" for yes
48
+ * the output should contain "2. Company X [buddypal]"
49
+ * the output should also contain "s. Save"
50
+ * I type "s" to save the database
51
+
52
+ * the output should contain "q. Quit"
29
53
  * I type "q" to quit
30
54
  * I wait a few seconds
31
55
  * I run keyrack interactively again
@@ -33,7 +57,23 @@ Feature: Console runner
33
57
  * the output should contain "Keyrack password:"
34
58
  * I type "secret"
35
59
  * I wait a few seconds
36
- * the output should contain "1. Twitter"
60
+ * the output should match /1\. .+Social.+/
61
+ * the output should also contain "2. Company X [buddypal]"
62
+ * I type "1" for Social
63
+ * the output should contain "1. Twitter [dudeguy]"
37
64
  * I type "1" for Twitter
38
65
  * my clipboard should contain "kittens"
66
+
67
+ * the output should contain "d. Delete entry"
68
+ * I type "d"
69
+ * the output should contain "1. Twitter [dudeguy]"
70
+ * I type "1"
71
+ * the output should contain "Are you sure?"
72
+ * I type "y"
73
+ * the output should contain "t. Top level menu"
74
+ * I type "t"
75
+
76
+ * the output should contain "Main Menu"
39
77
  * I type "q" to quit
78
+ * the output should contain "Really quit?" (since the database is dirty)
79
+ * I type "y"
@@ -25,6 +25,17 @@ Then /the output should contain "([^"]+)"/ do |expected|
25
25
  @output.should include(expected)
26
26
  end
27
27
 
28
+ Then %r{the output should match /([^/]+)/} do |expected|
29
+ # This won't work for escaped backslashes
30
+ if @slept
31
+ @slept = false
32
+ else
33
+ sleep 1
34
+ end
35
+ @output = @out.read_nonblock(255)
36
+ @output.should match(Regexp.new(expected))
37
+ end
38
+
28
39
  Then /the output should also contain "([^"]+)"/ do |expected|
29
40
  @output.should include(expected)
30
41
  end
@@ -8,17 +8,28 @@ module Keyrack
8
8
  @dirty = false
9
9
  end
10
10
 
11
- def add(site, username, password)
12
- @data[site] = { :username => username, :password => password }
11
+ def add(site, username, password, options = {})
12
+ hash = options[:group] ? @data[options[:group]] ||= {} : @data
13
+ hash[site] = { :username => username, :password => password }
13
14
  @dirty = true
14
15
  end
15
16
 
16
- def get(site)
17
- @data[site]
17
+ def get(site, options = {})
18
+ (options[:group] ? @data[options[:group]] : @data)[site]
18
19
  end
19
20
 
20
- def sites
21
- @data.keys
21
+ def sites(options = {})
22
+ hash = options[:group] ? @data[options[:group]] : @data
23
+ if hash
24
+ hash.keys.select { |k| hash[k].keys.include?(:username) }.sort
25
+ else
26
+ # new groups are empty
27
+ []
28
+ end
29
+ end
30
+
31
+ def groups
32
+ @data.keys.reject { |k| @data[k].keys.include?(:username) }.sort
22
33
  end
23
34
 
24
35
  def dirty?
@@ -32,6 +43,12 @@ module Keyrack
32
43
  @dirty = false
33
44
  end
34
45
 
46
+ def delete(site, options = {})
47
+ hash = options[:group] ? @data[options[:group]] : @data
48
+ hash.delete(site)
49
+ @dirty = true
50
+ end
51
+
35
52
  private
36
53
  def decrypt
37
54
  data = @store.read
@@ -54,15 +54,26 @@ module Keyrack
54
54
  end
55
55
 
56
56
  def main_loop
57
+ options = {}
57
58
  loop do
58
- case @ui.menu
59
+ choice = @ui.menu(options)
60
+
61
+ case choice
59
62
  when :new
60
63
  result = @ui.get_new_entry
61
- @database.add(result[:site], result[:username], result[:password])
64
+ @database.add(result[:site], result[:username], result[:password], options)
65
+ when :delete
66
+ @ui.delete_entry(options)
67
+ when :new_group
68
+ options = @ui.get_new_group
62
69
  when :save
63
70
  @database.save
64
71
  when :quit
65
72
  break
73
+ when Hash
74
+ options = choice
75
+ when :top
76
+ options = {}
66
77
  end
67
78
  end
68
79
  end
@@ -10,40 +10,72 @@ module Keyrack
10
10
  @highline.ask("Keyrack password: ") { |q| q.echo = false }
11
11
  end
12
12
 
13
- def menu
14
- entries = []
15
- choices = %w{n q}
16
- @database.sites.each_with_index do |site, i|
17
- entry = @database.get(site)
18
- entries << entry
19
- choices << "#{i+1}"
20
- @highline.say("% 2d. %s [%s]" % [i+1, site, entry[:username]])
13
+ def menu(options = {})
14
+ choices = {'n' => :new, 'q' => :quit}
15
+ index = 1
16
+
17
+ if !options[:group]
18
+ # Can't have subgroups (yet?).
19
+ @highline.say("=== #{@highline.color("Keyrack Main Menu", :yellow)} ===")
20
+ @database.groups.each do |group|
21
+ choices[index.to_s] = {:group => group}
22
+ @highline.say("% 2d. %s" % [index, @highline.color(group, :green)])
23
+ index += 1
24
+ end
25
+ else
26
+ @highline.say("===== #{@highline.color(options[:group], :green)} =====")
27
+ end
28
+
29
+ sites = @database.sites(options)
30
+ sites.each do |site|
31
+ entry = @database.get(site, options)
32
+ choices[index.to_s] = entry
33
+ @highline.say("% 2d. %s [%s]" % [index, site, entry[:username]])
34
+ index += 1
35
+ end
36
+
37
+ @highline.say(" n. New entry")
38
+ if !sites.empty?
39
+ choices['d'] = :delete
40
+ @highline.say(" d. Delete entry")
41
+ end
42
+ if !options[:group]
43
+ choices['g'] = :new_group
44
+ @highline.say(" g. New group")
45
+ else
46
+ choices['t'] = :top
47
+ @highline.say(" t. Top level menu")
21
48
  end
22
- @highline.say(" n. Add new")
23
49
  if @database.dirty?
50
+ choices['s'] = :save
24
51
  @highline.say(" s. Save")
25
- choices << "s"
26
52
  end
27
53
  @highline.say(" q. Quit")
28
- result = @highline.ask(" ? ") { |q| q.in = choices }
54
+ answer = @highline.ask(" ? ") { |q| q.in = choices.keys }
55
+ result = choices[answer]
29
56
  case result
30
- when "n"
31
- :new
32
- when "s"
33
- :save
34
- when "q"
35
- if @database.dirty? && !@highline.agree("Really quit? You have unsaved changes! [yn] ")
57
+ when Symbol
58
+ if result == :quit && @database.dirty? && !@highline.agree("Really quit? You have unsaved changes! [yn] ")
36
59
  nil
37
60
  else
38
- :quit
61
+ result
62
+ end
63
+ when Hash
64
+ if result.has_key?(:group)
65
+ result
66
+ else
67
+ Copier(result[:password])
68
+ @highline.say("The password has been copied to your clipboard.")
69
+ nil
39
70
  end
40
- else
41
- Copier(entries[result.to_i - 1][:password])
42
- @highline.say("The password has been copied to your clipboard.")
43
- nil
44
71
  end
45
72
  end
46
73
 
74
+ def get_new_group
75
+ group = @highline.ask("Group: ") { |q| q.validate = /^\w[\w\s]*$/ }
76
+ {:group => group}
77
+ end
78
+
47
79
  def get_new_entry
48
80
  result = {}
49
81
  result[:site] = @highline.ask("Label: ")
@@ -103,6 +135,28 @@ module Keyrack
103
135
 
104
136
  result
105
137
  end
138
+
139
+ def delete_entry(options = {})
140
+ choices = {'c' => :cancel}
141
+ index = 1
142
+ @highline.say("Choose entry to delete:")
143
+ @database.sites(options).each do |site|
144
+ entry = @database.get(site, options)
145
+ choices[index.to_s] = {:site => site, :username => entry[:username]}
146
+ @highline.say("% 2d. %s [%s]" % [index, site, entry[:username]])
147
+ index += 1
148
+ end
149
+ @highline.say(" c. Cancel")
150
+
151
+ answer = @highline.ask(" ? ") { |q| q.in = choices.keys }
152
+ result = choices[answer]
153
+ if result != :cancel
154
+ entry = @highline.color("#{result[:site]} [#{result[:username]}]", :red)
155
+ if @highline.agree("You're about to delete #{entry}. Are you sure? [yn] ")
156
+ @database.delete(result[:site], options)
157
+ end
158
+ end
159
+ end
106
160
  end
107
161
  end
108
162
  end
@@ -30,7 +30,16 @@ module Keyrack
30
30
  end
31
31
 
32
32
  def test_sites
33
+ @database.add('Blargh', 'dudeguy', 'secret', :group => "Junk")
33
34
  assert_equal(%w{Twitter}, @database.sites)
35
+ assert_equal(%w{Blargh}, @database.sites(:group => "Junk"))
36
+ assert_equal([], @database.sites(:group => "New group"))
37
+ end
38
+
39
+ def test_groups
40
+ assert_equal [], @database.groups
41
+ @database.add('Blargh', 'dudeguy', 'secret', :group => "Junk")
42
+ assert_equal %w{Junk}, @database.groups
34
43
  end
35
44
 
36
45
  def test_dirty
@@ -48,5 +57,24 @@ module Keyrack
48
57
  @database.save
49
58
  assert_equal 501, @database.sites.length
50
59
  end
60
+
61
+ def test_add_with_top_level_group
62
+ @database.add('Twitter', 'dudeguy', 'secret', :group => "Social")
63
+ expected = {:username => 'dudeguy', :password => 'secret'}
64
+ assert_equal expected, @database.get('Twitter', :group => "Social")
65
+ end
66
+
67
+ def test_delete
68
+ @database.delete('Twitter')
69
+ assert_equal [], @database.sites
70
+ assert @database.dirty?
71
+ end
72
+
73
+ def test_delete_group_entry
74
+ @database.add('Facebook', 'dudeguy', 'secret', :group => "Social")
75
+ @database.delete('Facebook', :group => 'Social')
76
+ assert_equal [], @database.sites(:group => 'Social')
77
+ assert_equal ['Twitter'], @database.sites
78
+ end
51
79
  end
52
80
  end
@@ -5,7 +5,7 @@ module Keyrack
5
5
  def setup
6
6
  @console = stub('console', {
7
7
  :get_password => 'secret',
8
- :database= => nil, :menu => nil,
8
+ :database= => nil, :menu => :quit,
9
9
  :get_new_entry => {:site => "Foo", :username => "bar", :password => "baz"}
10
10
  })
11
11
  UI::Console.stubs(:new).returns(@console)
@@ -40,10 +40,23 @@ module Keyrack
40
40
 
41
41
  @console.expects(:menu).returns(:new).in_sequence(seq)
42
42
  @console.expects(:get_new_entry).returns({:site => "Foo", :username => "bar", :password => "baz"}).in_sequence(seq)
43
- @database.expects(:add).with("Foo", "bar", "baz")
43
+ @database.expects(:add).with("Foo", "bar", "baz", {})
44
44
  @console.expects(:menu).returns(nil).in_sequence(seq)
45
45
  @console.expects(:menu).returns(:save).in_sequence(seq)
46
46
  @database.expects(:save).in_sequence(seq)
47
+ @console.expects(:menu).returns(:delete).in_sequence(seq)
48
+ @console.expects(:delete_entry).with({}).in_sequence(seq)
49
+ @console.expects(:menu).returns(:new_group).in_sequence(seq)
50
+ @console.expects(:get_new_group).returns(:group => 'Blah').in_sequence(seq)
51
+ @console.expects(:menu).with(:group => 'Blah').returns(:top).in_sequence(seq)
52
+ @console.expects(:menu).returns(:group => 'Huge').in_sequence(seq)
53
+ @console.expects(:menu).with(:group => 'Huge').returns(nil).in_sequence(seq)
54
+ @console.expects(:menu).with(:group => 'Huge').returns(:new).in_sequence(seq)
55
+ @console.expects(:get_new_entry).returns({:site => "Bar", :username => "bar", :password => "baz"}).in_sequence(seq)
56
+ @database.expects(:add).with("Bar", "bar", "baz", :group => 'Huge')
57
+ @console.expects(:menu).with(:group => "Huge").returns(:delete).in_sequence(seq)
58
+ @console.expects(:delete_entry).with(:group => 'Huge').in_sequence(seq)
59
+ @console.expects(:menu).with(:group => 'Huge').returns(:top).in_sequence(seq)
47
60
  @console.expects(:menu).returns(:quit).in_sequence(seq)
48
61
 
49
62
  runner = Runner.new(["-d", keyrack_dir])
@@ -67,10 +80,9 @@ module Keyrack
67
80
  rsa.expects(:public_encrypt).with(dump).returns("encrypted dump")
68
81
 
69
82
  # Store setup
70
- store_path = 'database'
71
- @console.expects(:store_setup).returns('type' => 'filesystem', 'path' => store_path).in_sequence(seq)
83
+ @console.expects(:store_setup).returns('type' => 'filesystem', 'path' => 'database').in_sequence(seq)
72
84
  store = mock('filesystem store')
73
- Store::Filesystem.expects(:new).with('path' => store_path).returns(store).in_sequence(seq)
85
+ Store::Filesystem.expects(:new).with('path' => File.join(keyrack_dir, 'database')).returns(store).in_sequence(seq)
74
86
 
75
87
  Database.expects(:new).with('foobar', 'barfoo', store).returns(@database).in_sequence(seq)
76
88
  @console.expects(:database=).with(@database).in_sequence(seq)
@@ -91,7 +103,7 @@ module Keyrack
91
103
  assert File.exist?(expected_config_file)
92
104
  expected_config = {
93
105
  'rsa' => expected_rsa_file, 'aes' => expected_aes_file,
94
- 'store' => { 'type' => 'filesystem', 'path' => store_path }
106
+ 'store' => { 'type' => 'filesystem', 'path' => File.join(keyrack_dir, 'database') }
95
107
  }
96
108
  assert_equal expected_config, YAML.load_file(expected_config_file)
97
109
  end
@@ -4,199 +4,246 @@ module Keyrack
4
4
  module UI
5
5
  class TestConsole < Test::Unit::TestCase
6
6
  def setup
7
- @database = stub('database', :sites => %w{Twitter}, :dirty? => false) do
8
- stubs(:get).with('Twitter').returns({
7
+ @database = stub('database', :sites => %w{Twitter}, :groups => [], :dirty? => false) do
8
+ stubs(:get).with('Twitter', {}).returns({
9
9
  :username => 'username', :password => 'password'
10
10
  })
11
11
  end
12
+ @highline = stub('highline')
13
+ @highline.stubs(:color).with("Keyrack Main Menu", :yellow).returns("yellowKeyrack Main Menu")
14
+ @highline.stubs(:say)
15
+ HighLine.expects(:new).returns(@highline)
16
+ @console = Console.new
12
17
  end
13
18
 
14
19
  def test_select_entry_from_menu
15
- highline = mock('highline')
16
- HighLine.expects(:new).returns(highline)
17
- console = Console.new
18
- console.database = @database
19
-
20
- highline.expects(:say).with(" 1. Twitter [username]")
21
- highline.expects(:say).with(" n. Add new")
22
- highline.expects(:say).with(" q. Quit")
20
+ @console.database = @database
21
+ @highline.expects(:say).with("=== yellowKeyrack Main Menu ===")
22
+ @highline.expects(:say).with(" 1. Twitter [username]")
23
+ @highline.expects(:say).with(" n. New entry")
24
+ @highline.expects(:say).with(" d. Delete entry")
25
+ @highline.expects(:say).with(" g. New group")
26
+ @highline.expects(:say).with(" q. Quit")
23
27
 
24
28
  question = mock('question')
25
- question.expects(:in=).with(%w{n q 1})
26
- highline.expects(:ask).yields(question).returns('1')
27
- console.expects(:Copier).with('password')
28
- highline.expects(:say).with("The password has been copied to your clipboard.")
29
- assert_nil console.menu
29
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d g}) }).returns('1')
30
+ @console.expects(:Copier).with('password')
31
+ @highline.expects(:say).with("The password has been copied to your clipboard.")
32
+ assert_nil @console.menu
30
33
  end
31
34
 
32
35
  def test_select_new_from_menu
33
- highline = mock('highline')
34
- HighLine.expects(:new).returns(highline)
35
- console = Console.new
36
- console.database = @database
36
+ @console.database = @database
37
+
38
+ # === yellowKeyrack Main Menu ===
39
+ # 1. Twitter [username]
40
+ # n. New entry
41
+ # d. Delete entry
42
+ # g. New group
43
+ # q. Quit
44
+
45
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d g}) }).returns('n')
46
+ assert_equal :new, @console.menu
47
+ end
37
48
 
38
- highline.expects(:say).with(" 1. Twitter [username]")
39
- highline.expects(:say).with(" n. Add new")
40
- highline.expects(:say).with(" q. Quit")
49
+ def test_select_delete_from_menu
50
+ @console.database = @database
51
+
52
+ # === yellowKeyrack Main Menu ===
53
+ # 1. Twitter [username]
54
+ # n. New entry
55
+ # d. Delete entry
56
+ # g. New group
57
+ # q. Quit
41
58
 
42
59
  question = mock('question')
43
- question.expects(:in=).with(%w{n q 1})
44
- highline.expects(:ask).yields(question).returns('n')
45
- assert_equal :new, console.menu
60
+ question.expects(:in=).with(%w{n q 1 d g})
61
+ @highline.expects(:ask).yields(question).returns('d')
62
+ assert_equal :delete, @console.menu
46
63
  end
47
64
 
48
65
  def test_select_quit_from_menu
49
- highline = mock('highline')
50
- HighLine.expects(:new).returns(highline)
51
- console = Console.new
52
- console.database = @database
66
+ @console.database = @database
53
67
 
54
- highline.expects(:say).with(" 1. Twitter [username]")
55
- highline.expects(:say).with(" n. Add new")
56
- highline.expects(:say).with(" q. Quit")
68
+ # === yellowKeyrack Main Menu ===
69
+ # 1. Twitter [username]
70
+ # n. New entry
71
+ # d. Delete entry
72
+ # g. New group
73
+ # q. Quit
57
74
 
58
- question = mock('question')
59
- question.expects(:in=).with(%w{n q 1})
60
- highline.expects(:ask).yields(question).returns('q')
61
- assert_equal :quit, console.menu
75
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d g}) }).returns('q')
76
+ assert_equal :quit, @console.menu
62
77
  end
63
78
 
64
79
  def test_select_quit_from_menu_when_database_is_dirty
65
- highline = mock('highline')
66
- HighLine.expects(:new).returns(highline)
67
- console = Console.new
68
- console.database = @database
80
+ @console.database = @database
69
81
  @database.stubs(:dirty?).returns(true)
70
82
 
71
- highline.expects(:say).with(" 1. Twitter [username]")
72
- highline.expects(:say).with(" n. Add new")
73
- highline.expects(:say).with(" s. Save")
74
- highline.expects(:say).with(" q. Quit")
75
-
76
- question = mock('question', :in= => nil)
77
- highline.expects(:ask).yields(question).returns('q')
78
- highline.expects(:agree).with("Really quit? You have unsaved changes! [yn] ").returns(false)
79
- assert_equal nil, console.menu
83
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d g s}) }).returns('q')
84
+ @highline.expects(:agree).with("Really quit? You have unsaved changes! [yn] ").returns(false)
85
+ assert_equal nil, @console.menu
80
86
  end
81
87
 
82
88
  def test_select_save_from_menu
83
- highline = mock('highline')
84
- HighLine.expects(:new).returns(highline)
85
- console = Console.new
86
- console.database = @database
89
+ @console.database = @database
87
90
  @database.stubs(:dirty?).returns(true)
88
91
 
89
- highline.expects(:say).with(" 1. Twitter [username]")
90
- highline.expects(:say).with(" n. Add new")
91
- highline.expects(:say).with(" s. Save")
92
- highline.expects(:say).with(" q. Quit")
92
+ @highline.expects(:say).with(" s. Save")
93
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d g s}) }).returns('s')
94
+ assert_equal :save, @console.menu
95
+ end
93
96
 
94
- question = mock('question')
95
- question.expects(:in=).with(%w{n q 1 s})
96
- highline.expects(:ask).yields(question).returns('s')
97
- assert_equal :save, console.menu
97
+ def test_select_group_from_menu
98
+ @console.database = @database
99
+ @database.stubs(:groups).returns(["Blargh"])
100
+
101
+ @highline.expects(:color).with('Blargh', :green).returns('greenBlargh')
102
+ @highline.expects(:say).with(" 1. greenBlargh")
103
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 2 d g}) }).returns('1')
104
+ assert_equal({:group => 'Blargh'}, @console.menu)
98
105
  end
99
106
 
100
- def test_get_password
101
- highline = mock('highline')
102
- HighLine.expects(:new).returns(highline)
103
- console = Console.new
107
+ def test_select_entry_from_group_menu
108
+ @console.database = @database
109
+ @database.expects(:sites).with(:group => "Foo").returns(["Facebook"])
110
+ @database.expects(:get).with('Facebook', :group => "Foo").returns({:username => 'username', :password => 'password'})
111
+
112
+ @highline.expects(:color).with("Foo", :green).returns("greenFoo")
113
+ @highline.expects(:say).with("===== greenFoo =====")
114
+ @highline.expects(:say).with(" 1. Facebook [username]")
115
+ @highline.expects(:say).with(" n. New entry")
116
+ @highline.expects(:say).with(" d. Delete entry")
117
+ @highline.expects(:say).with(" t. Top level menu")
118
+ @highline.expects(:say).with(" q. Quit")
119
+
120
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d t}) }).returns('1')
121
+ @console.expects(:Copier).with('password')
122
+ @highline.expects(:say).with("The password has been copied to your clipboard.")
123
+ assert_nil @console.menu(:group => 'Foo')
124
+ end
104
125
 
126
+ def test_get_password
105
127
  question = mock('question')
106
128
  question.expects(:echo=).with(false)
107
- highline.expects(:ask).with("Keyrack password: ").yields(question).returns("foobar")
108
- assert_equal "foobar", console.get_password
129
+ @highline.expects(:ask).with("Keyrack password: ").yields(question).returns("foobar")
130
+ assert_equal "foobar", @console.get_password
109
131
  end
110
132
 
111
133
  def test_get_new_entry_with_manual_password
112
- highline = mock('highline')
113
- HighLine.expects(:new).returns(highline)
114
- console = Console.new
115
-
116
134
  seq = sequence("new entry")
117
- highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
118
- highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
119
- highline.expects(:agree).with("Generate password? [yn] ").returns(false).in_sequence(seq)
120
- highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
121
- highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("bar").in_sequence(seq)
122
- highline.expects(:say).with("Passwords didn't match. Try again!").in_sequence(seq)
123
- highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
124
- highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
125
- assert_equal({:site => "Foo", :username => "bar", :password => "baz"}, console.get_new_entry)
135
+ @highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
136
+ @highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
137
+ @highline.expects(:agree).with("Generate password? [yn] ").returns(false).in_sequence(seq)
138
+ @highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
139
+ @highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("bar").in_sequence(seq)
140
+ @highline.expects(:say).with("Passwords didn't match. Try again!").in_sequence(seq)
141
+ @highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
142
+ @highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
143
+ assert_equal({:site => "Foo", :username => "bar", :password => "baz"}, @console.get_new_entry)
126
144
  end
127
145
 
128
146
  def test_get_new_entry_generated_password
129
- highline = mock('highline')
130
- HighLine.expects(:new).returns(highline)
131
- console = Console.new
132
-
133
147
  seq = sequence("new entry")
134
- highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
135
- highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
136
- highline.expects(:agree).with("Generate password? [yn] ").returns(true).in_sequence(seq)
148
+ @highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
149
+ @highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
150
+ @highline.expects(:agree).with("Generate password? [yn] ").returns(true).in_sequence(seq)
137
151
  Utils.expects(:generate_password).returns('foobar').in_sequence(seq)
138
- highline.expects(:color).with('foobar', :blue).returns('bluefoobar').in_sequence(seq)
139
- highline.expects(:agree).with("Generated bluefoobar. Sound good? [yn] ").returns(false).in_sequence(seq)
152
+ @highline.expects(:color).with('foobar', :blue).returns('bluefoobar').in_sequence(seq)
153
+ @highline.expects(:agree).with("Generated bluefoobar. Sound good? [yn] ").returns(false).in_sequence(seq)
140
154
  Utils.expects(:generate_password).returns('foobar').in_sequence(seq)
141
- highline.expects(:color).with('foobar', :blue).returns('bluefoobar').in_sequence(seq)
142
- highline.expects(:agree).with("Generated bluefoobar. Sound good? [yn] ").returns(true).in_sequence(seq)
143
- assert_equal({:site => "Foo", :username => "bar", :password => "foobar"}, console.get_new_entry)
155
+ @highline.expects(:color).with('foobar', :blue).returns('bluefoobar').in_sequence(seq)
156
+ @highline.expects(:agree).with("Generated bluefoobar. Sound good? [yn] ").returns(true).in_sequence(seq)
157
+ assert_equal({:site => "Foo", :username => "bar", :password => "foobar"}, @console.get_new_entry)
144
158
  end
145
159
 
146
160
  def test_display_first_time_notice
147
- highline = mock('highline')
148
- HighLine.expects(:new).returns(highline)
149
- console = Console.new
150
-
151
- highline.expects(:say).with("This looks like your first time using Keyrack. I'll need to ask you a few questions first.")
152
- console.display_first_time_notice
161
+ @highline.expects(:say).with("This looks like your first time using Keyrack. I'll need to ask you a few questions first.")
162
+ @console.display_first_time_notice
153
163
  end
154
164
 
155
165
  def test_rsa_setup
156
- highline = mock('highline')
157
- HighLine.expects(:new).returns(highline)
158
- console = Console.new
159
-
160
166
  seq = sequence("rsa setup")
161
- highline.expects(:ask).with("New passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
162
- highline.expects(:ask).with("Confirm passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('small').in_sequence(seq)
163
- highline.expects(:say).with("Passphrases didn't match.").in_sequence(seq)
164
- highline.expects(:ask).with("New passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
165
- highline.expects(:ask).with("Confirm passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
167
+ @highline.expects(:ask).with("New passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
168
+ @highline.expects(:ask).with("Confirm passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('small').in_sequence(seq)
169
+ @highline.expects(:say).with("Passphrases didn't match.").in_sequence(seq)
170
+ @highline.expects(:ask).with("New passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
171
+ @highline.expects(:ask).with("Confirm passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
166
172
  expected = {'password' => 'huge', 'path' => 'rsa'}
167
- assert_equal expected, console.rsa_setup
173
+ assert_equal expected, @console.rsa_setup
168
174
  end
169
175
 
170
176
  def test_store_setup_for_filesystem
171
- highline = mock('highline')
172
- HighLine.expects(:new).returns(highline)
173
- console = Console.new
174
-
175
- highline.expects(:choose).yields(mock {
177
+ @highline.expects(:choose).yields(mock {
176
178
  expects(:header=).with("Choose storage type:")
177
179
  expects(:choices).with("filesystem", "ssh")
178
180
  }).returns("filesystem")
179
181
 
180
182
  expected = {'type' => 'filesystem', 'path' => 'database'}
181
- assert_equal expected, console.store_setup
183
+ assert_equal expected, @console.store_setup
182
184
  end
183
185
 
184
186
  def test_store_setup_for_ssh
185
- highline = mock('highline')
186
- HighLine.expects(:new).returns(highline)
187
- console = Console.new
188
-
189
187
  seq = sequence("store setup")
190
- highline.expects(:choose).yields(mock {
188
+ @highline.expects(:choose).yields(mock {
191
189
  expects(:header=).with("Choose storage type:")
192
190
  expects(:choices).with("filesystem", "ssh")
193
191
  }).returns("ssh").in_sequence(seq)
194
- highline.expects(:ask).with("Host: ").returns("example.com").in_sequence(seq)
195
- highline.expects(:ask).with("User: ").returns("dudeguy").in_sequence(seq)
196
- highline.expects(:ask).with("Remote path: ").returns(".keyrack/database").in_sequence(seq)
192
+ @highline.expects(:ask).with("Host: ").returns("example.com").in_sequence(seq)
193
+ @highline.expects(:ask).with("User: ").returns("dudeguy").in_sequence(seq)
194
+ @highline.expects(:ask).with("Remote path: ").returns(".keyrack/database").in_sequence(seq)
197
195
 
198
196
  expected = {'type' => 'ssh', 'host' => 'example.com', 'user' => 'dudeguy', 'path' => '.keyrack/database'}
199
- assert_equal expected, console.store_setup
197
+ assert_equal expected, @console.store_setup
198
+ end
199
+
200
+ def test_get_new_group
201
+ @highline.expects(:ask).with("Group: ").yields(mock {
202
+ expects(:validate=).with(/^\w[\w\s]*$/)
203
+ }).returns("Foo")
204
+ assert_equal({:group => "Foo"}, @console.get_new_group)
205
+ end
206
+
207
+ def test_delete_entry
208
+ @console.database = @database
209
+ @database.stubs(:sites).returns(%w{Twitter Facebook})
210
+ @database.stubs(:get).with('Facebook', {}).returns({
211
+ :username => 'username', :password => 'password'
212
+ })
213
+
214
+ seq = sequence("deleting")
215
+ @highline.expects(:say).with("Choose entry to delete:").in_sequence(seq)
216
+ @highline.expects(:say).with(" 1. Twitter [username]").in_sequence(seq)
217
+ @highline.expects(:say).with(" 2. Facebook [username]").in_sequence(seq)
218
+ @highline.expects(:say).with(" c. Cancel").in_sequence(seq)
219
+ @highline.expects(:ask).yields(mock {
220
+ expects(:in=).with(%w{c 1 2})
221
+ }).returns('1').in_sequence(seq)
222
+ @highline.expects(:color).with("Twitter [username]", :red).returns("redTwitter").in_sequence(seq)
223
+ @highline.expects(:agree).with("You're about to delete redTwitter. Are you sure? [yn] ").returns(true).in_sequence(seq)
224
+ @database.expects(:delete).with("Twitter", {}).in_sequence(seq)
225
+ @console.delete_entry
226
+ end
227
+
228
+ def test_delete_group_entry
229
+ @console.database = @database
230
+ @database.stubs(:sites).returns(%w{Quora Foursquare})
231
+ @database.stubs(:get).with(kind_of(String), {:group => 'Social'}).returns({
232
+ :username => 'username', :password => 'password'
233
+ })
234
+
235
+ seq = sequence("deleting")
236
+ @highline.expects(:say).with("Choose entry to delete:").in_sequence(seq)
237
+ @highline.expects(:say).with(" 1. Quora [username]").in_sequence(seq)
238
+ @highline.expects(:say).with(" 2. Foursquare [username]").in_sequence(seq)
239
+ @highline.expects(:say).with(" c. Cancel").in_sequence(seq)
240
+ @highline.expects(:ask).yields(mock {
241
+ expects(:in=).with(%w{c 1 2})
242
+ }).returns('2').in_sequence(seq)
243
+ @highline.expects(:color).with("Foursquare [username]", :red).returns("redFoursquare").in_sequence(seq)
244
+ @highline.expects(:agree).with("You're about to delete redFoursquare. Are you sure? [yn] ").returns(true).in_sequence(seq)
245
+ @database.expects(:delete).with("Foursquare", :group => 'Social').in_sequence(seq)
246
+ @console.delete_entry(:group => 'Social')
200
247
  end
201
248
  end
202
249
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 0
9
- version: 0.2.0
8
+ - 1
9
+ version: 0.2.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jeremy Stephens
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-04 00:00:00 -06:00
17
+ date: 2011-01-05 00:00:00 -06:00
18
18
  default_executable: keyrack
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -134,6 +134,7 @@ extensions: []
134
134
  extra_rdoc_files:
135
135
  - LICENSE.txt
136
136
  - README.rdoc
137
+ - TODO
137
138
  files:
138
139
  - .document
139
140
  - .rvmrc
@@ -143,6 +144,7 @@ files:
143
144
  - LICENSE.txt
144
145
  - README.rdoc
145
146
  - Rakefile
147
+ - TODO
146
148
  - VERSION
147
149
  - bin/keyrack
148
150
  - features/console.feature
@@ -184,7 +186,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
184
186
  requirements:
185
187
  - - ">="
186
188
  - !ruby/object:Gem::Version
187
- hash: -415657060610893124
189
+ hash: -45771557779572669
188
190
  segments:
189
191
  - 0
190
192
  version: "0"