keyrack 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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"