keyrack 0.3.0.pre → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +8 -15
  4. data/Guardfile +6 -0
  5. data/LICENSE.txt +4 -2
  6. data/Rakefile +2 -56
  7. data/keyrack.gemspec +22 -104
  8. data/lib/keyrack.rb +9 -1
  9. data/lib/keyrack/database.rb +64 -98
  10. data/lib/keyrack/event.rb +13 -0
  11. data/lib/keyrack/exceptions.rb +4 -0
  12. data/lib/keyrack/group.rb +225 -0
  13. data/lib/keyrack/migrator.rb +45 -0
  14. data/lib/keyrack/runner.rb +98 -44
  15. data/lib/keyrack/site.rb +92 -0
  16. data/lib/keyrack/ui/console.rb +234 -95
  17. data/lib/keyrack/utils.rb +0 -18
  18. data/lib/keyrack/version.rb +3 -0
  19. data/test/fixtures/database-3.dat +0 -0
  20. data/test/helper.rb +11 -1
  21. data/test/integration/test_interactive_console.rb +139 -0
  22. data/test/unit/store/test_filesystem.rb +21 -0
  23. data/test/unit/store/test_ssh.rb +32 -0
  24. data/test/unit/test_database.rb +201 -0
  25. data/test/unit/test_event.rb +41 -0
  26. data/test/unit/test_group.rb +703 -0
  27. data/test/unit/test_migrator.rb +105 -0
  28. data/test/unit/test_runner.rb +407 -0
  29. data/test/unit/test_site.rb +181 -0
  30. data/test/unit/test_store.rb +13 -0
  31. data/test/unit/test_utils.rb +8 -0
  32. data/test/unit/ui/test_console.rb +495 -0
  33. metadata +98 -94
  34. data/Gemfile.lock +0 -45
  35. data/TODO +0 -4
  36. data/VERSION +0 -1
  37. data/features/console.feature +0 -103
  38. data/features/step_definitions/keyrack_steps.rb +0 -61
  39. data/features/support/env.rb +0 -16
  40. data/test/fixtures/aes +0 -0
  41. data/test/fixtures/config.yml +0 -4
  42. data/test/fixtures/id_rsa +0 -54
  43. data/test/keyrack/store/test_filesystem.rb +0 -25
  44. data/test/keyrack/store/test_ssh.rb +0 -36
  45. data/test/keyrack/test_database.rb +0 -111
  46. data/test/keyrack/test_runner.rb +0 -111
  47. data/test/keyrack/test_store.rb +0 -15
  48. data/test/keyrack/test_utils.rb +0 -41
  49. data/test/keyrack/ui/test_console.rb +0 -308
@@ -0,0 +1,181 @@
1
+ require 'helper'
2
+
3
+ class TestSite < Test::Unit::TestCase
4
+ def new_site(*args)
5
+ Keyrack::Site.new(*args)
6
+ end
7
+
8
+ test "creating new site" do
9
+ site = new_site("Enterprise", "picard", "livingston")
10
+ assert_equal "Enterprise", site.name
11
+ end
12
+
13
+ test "name setter" do
14
+ site = new_site("Enterprise", "picard", "livingston")
15
+ site.name = "NCC1701D"
16
+ assert_equal "NCC1701D", site.name
17
+ end
18
+
19
+ test "username" do
20
+ site = new_site("Enterprise", "picard", "livingston")
21
+ assert_equal "picard", site.username
22
+ end
23
+
24
+ test "username setter" do
25
+ site = new_site("Enterprise", "picard", "livingston")
26
+ site.username = "jean_luc"
27
+ assert_equal "jean_luc", site.username
28
+ end
29
+
30
+ test "password" do
31
+ site = new_site("Enterprise", "picard", "livingston")
32
+ assert_equal "livingston", site.password
33
+ end
34
+
35
+ test "password setter" do
36
+ site = new_site("Enterprise", "picard", "livingston")
37
+ site.password = "crusher"
38
+ assert_equal "crusher", site.password
39
+ end
40
+
41
+ test "loading site from hash" do
42
+ hash = {
43
+ 'name' => 'Enterprise',
44
+ 'username' => 'picard',
45
+ 'password' => 'livingston'
46
+ }
47
+ site = new_site(hash)
48
+ assert_equal 'Enterprise', site.name
49
+ assert_equal 'picard', site.username
50
+ assert_equal 'livingston', site.password
51
+ end
52
+
53
+ test "loading site from hash with missing name" do
54
+ hash = {
55
+ 'username' => 'picard',
56
+ 'password' => 'livingston'
57
+ }
58
+ assert_raises(ArgumentError) do
59
+ site = new_site(hash)
60
+ end
61
+ end
62
+
63
+ test "loading site from hash with non-string name" do
64
+ hash = {
65
+ 'name' => [123],
66
+ 'username' => 'picard',
67
+ 'password' => 'livingston'
68
+ }
69
+ assert_raises(ArgumentError) do
70
+ site = new_site(hash)
71
+ end
72
+ end
73
+
74
+ test "loading site from hash with missing username" do
75
+ hash = {
76
+ 'name' => 'Enterprise',
77
+ 'password' => 'livingston'
78
+ }
79
+ assert_raises(ArgumentError) do
80
+ site = new_site(hash)
81
+ end
82
+ end
83
+
84
+ test "loading site from hash with non-string username" do
85
+ hash = {
86
+ 'name' => 'Enterprise',
87
+ 'username' => [123],
88
+ 'password' => 'livingston'
89
+ }
90
+ assert_raises(ArgumentError) do
91
+ site = new_site(hash)
92
+ end
93
+ end
94
+
95
+ test "loading site from hash with missing password" do
96
+ hash = {
97
+ 'name' => 'Enterprise',
98
+ 'username' => 'picard'
99
+ }
100
+ assert_raises(ArgumentError) do
101
+ site = new_site(hash)
102
+ end
103
+ end
104
+
105
+ test "loading site from hash with non-string password" do
106
+ hash = {
107
+ 'name' => 'Enterprise',
108
+ 'username' => 'picard',
109
+ 'password' => [123]
110
+ }
111
+ assert_raises(ArgumentError) do
112
+ site = new_site(hash)
113
+ end
114
+ end
115
+
116
+ test "name change event" do
117
+ site = new_site("Enterprise", "picard", "livingston")
118
+
119
+ called = false
120
+ site.after_event do |event|
121
+ called = true
122
+ assert_equal 'change', event.name
123
+ assert_same site, event.owner
124
+ assert_equal 'name', event.attribute_name
125
+ assert_equal 'Enterprise', event.previous_value
126
+ assert_equal 'NCC1701D', event.new_value
127
+ end
128
+ site.name = "NCC1701D"
129
+ assert called
130
+ end
131
+
132
+ test "password changed callback" do
133
+ site = new_site("Enterprise", "picard", "livingston")
134
+
135
+ called = false
136
+ site.after_event do |event|
137
+ called = true
138
+ assert_same site, event.owner
139
+ assert_equal 'change', event.name
140
+ assert_equal 'password', event.attribute_name
141
+ assert_equal 'livingston', event.previous_value
142
+ assert_equal 'crusher', event.new_value
143
+ end
144
+ site.password = "crusher"
145
+ assert called
146
+ end
147
+
148
+ test "username changed callback" do
149
+ site = new_site("Enterprise", "picard", "livingston")
150
+
151
+ called = false
152
+ site.after_event do |event|
153
+ called = true
154
+ assert_same site, event.owner
155
+ assert_equal 'change', event.name
156
+ assert_equal 'username', event.attribute_name
157
+ assert_equal 'picard', event.previous_value
158
+ assert_equal 'jean_luc', event.new_value
159
+ end
160
+ site.username = "jean_luc"
161
+ assert called
162
+ end
163
+
164
+ test "serializing to yaml" do
165
+ site = new_site("Enterprise", "picard", "livingston")
166
+ expected = {
167
+ 'name' => 'Enterprise',
168
+ 'username' => 'picard',
169
+ 'password' => 'livingston'
170
+ }.to_yaml
171
+ assert_equal expected, site.to_yaml
172
+ end
173
+
174
+ test "sites with same name and username are equal" do
175
+ site_1 = new_site("Enterprise", "picard", "livingston")
176
+ site_2 = new_site("Enterprise", "picard", "crusher")
177
+ site_3 = new_site("Enterprise", "jean_luc", "crusher")
178
+ assert_equal site_1, site_2
179
+ assert_not_equal site_1, site_3
180
+ end
181
+ end
@@ -0,0 +1,13 @@
1
+ require 'helper'
2
+
3
+ class TestStore < Test::Unit::TestCase
4
+ def test_get_filesystem
5
+ assert_equal Keyrack::Store::Filesystem, Keyrack::Store[:filesystem]
6
+ assert_equal Keyrack::Store::Filesystem, Keyrack::Store['filesystem']
7
+ end
8
+
9
+ def test_get_ssh
10
+ assert_equal Keyrack::Store::SSH, Keyrack::Store[:ssh]
11
+ assert_equal Keyrack::Store::SSH, Keyrack::Store['ssh']
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ require 'helper'
2
+
3
+ class TestUtils < Test::Unit::TestCase
4
+ def test_generate_password
5
+ result = Keyrack::Utils.generate_password
6
+ assert_match /^[!-~]{8}$/, result
7
+ end
8
+ end
@@ -0,0 +1,495 @@
1
+ require 'helper'
2
+
3
+ class TestConsole < Test::Unit::TestCase
4
+ def setup
5
+ @twitter = stub('Twitter', {
6
+ :name => 'Twitter',
7
+ :username => 'tweeb',
8
+ :password => 'secret'
9
+ })
10
+ @google_1 = stub('Google 1', {
11
+ :name => 'Google',
12
+ :username => 'catfan',
13
+ :password => 'kitty'
14
+ })
15
+ @google_2 = stub('Google 2', {
16
+ :name => 'Google',
17
+ :username => 'dogfan',
18
+ :password => 'puppy'
19
+ })
20
+ @top_group = stub('top group', {
21
+ :sites => [@twitter, @google_1, @google_2],
22
+ :group_names => []
23
+ })
24
+ @top_group.stubs(:site).with(0).returns(@twitter)
25
+ @top_group.stubs(:site).with(1).returns(@google_1)
26
+ @top_group.stubs(:site).with(2).returns(@google_2)
27
+
28
+ @highline = stub('highline')
29
+ @highline.stubs(:color).with("Keyrack Main Menu", instance_of(Symbol)).
30
+ returns("Keyrack Main Menu")
31
+ #@highline.stubs(:say)
32
+ HighLine.expects(:new).returns(@highline)
33
+ @console = Keyrack::UI::Console.new
34
+
35
+ HighLine::SystemExtensions.stubs(:terminal_size).returns([20, 20])
36
+ end
37
+
38
+ test "select login from menu" do
39
+ seq = sequence('say')
40
+ @highline.expects(:say).with("=== Keyrack Main Menu ===")
41
+ @highline.expects(:say).with("1. Twitter [tweeb]")
42
+ @highline.expects(:say).with("2. Google [catfan]")
43
+ @highline.expects(:say).with("3. Google [dogfan]")
44
+ @highline.expects(:say).with("Mode: copy")
45
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [m]ode [q]uit")
46
+
47
+ question = mock('question')
48
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 2 3 e g}) }).returns('1')
49
+ Clipboard.expects(:copy).with('secret')
50
+ @highline.expects(:say).with("The password has been copied to your clipboard.")
51
+ assert_nil @console.menu(:group => @top_group, :at_top => true)
52
+ end
53
+
54
+ test "select entry from menu in print mode" do
55
+ seq = sequence('say')
56
+ @console.mode = :print
57
+ @highline.expects(:say).with("=== Keyrack Main Menu ===")
58
+ @highline.expects(:say).with("1. Twitter [tweeb]")
59
+ @highline.expects(:say).with("2. Google [catfan]")
60
+ @highline.expects(:say).with("3. Google [dogfan]")
61
+ @highline.expects(:say).with("Mode: print")
62
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [m]ode [q]uit")
63
+
64
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 2 3 e g}) }).returns('1')
65
+ @highline.expects(:color).with('secret', instance_of(Symbol)).
66
+ returns('secret').in_sequence(seq)
67
+ question = mock do
68
+ expects(:echo=).with(false)
69
+ if HighLine::SystemExtensions::CHARACTER_MODE != 'stty'
70
+ expects(:character=).with(true)
71
+ expects(:overwrite=).with(true)
72
+ end
73
+ end
74
+ @highline.expects(:ask).
75
+ with('Here you go: secret. Done? ').
76
+ yields(question).
77
+ returns('')
78
+
79
+ assert_nil @console.menu(:group => @top_group, :at_top => true)
80
+ end
81
+
82
+ test "select new from menu" do
83
+ @highline.expects(:say).with("=== Keyrack Main Menu ===")
84
+ @highline.expects(:say).with("1. Twitter [tweeb]")
85
+ @highline.expects(:say).with("2. Google [catfan]")
86
+ @highline.expects(:say).with("3. Google [dogfan]")
87
+ @highline.expects(:say).with("Mode: copy")
88
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [m]ode [q]uit")
89
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 2 3 e g}) }).returns('n')
90
+ assert_equal :new, @console.menu(:group => @top_group, :at_top => true)
91
+ end
92
+
93
+ test "select edit from menu" do
94
+ @highline.expects(:say).with("=== Keyrack Main Menu ===")
95
+ @highline.expects(:say).with("1. Twitter [tweeb]")
96
+ @highline.expects(:say).with("2. Google [catfan]")
97
+ @highline.expects(:say).with("3. Google [dogfan]")
98
+ @highline.expects(:say).with("Mode: copy")
99
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [m]ode [q]uit")
100
+ question = mock('question')
101
+ question.expects(:in=).with(%w{n q m 1 2 3 e g})
102
+ @highline.expects(:ask).yields(question).returns('e')
103
+ assert_equal :edit, @console.menu(:group => @top_group, :at_top => true)
104
+ end
105
+
106
+ test "select quit from menu" do
107
+ @highline.expects(:say).with("=== Keyrack Main Menu ===")
108
+ @highline.expects(:say).with("1. Twitter [tweeb]")
109
+ @highline.expects(:say).with("2. Google [catfan]")
110
+ @highline.expects(:say).with("3. Google [dogfan]")
111
+ @highline.expects(:say).with("Mode: copy")
112
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [m]ode [q]uit")
113
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 2 3 e g}) }).returns('q')
114
+ assert_equal :quit, @console.menu(:group => @top_group, :at_top => true)
115
+ end
116
+
117
+ test "select quit from menu when database is dirty" do
118
+ @highline.expects(:say).with("=== Keyrack Main Menu ===")
119
+ @highline.expects(:say).with("1. Twitter [tweeb]")
120
+ @highline.expects(:say).with("2. Google [catfan]")
121
+ @highline.expects(:say).with("3. Google [dogfan]")
122
+ @highline.expects(:say).with("Mode: copy")
123
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [s]ave [m]ode [q]uit")
124
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 2 3 e g s}) }).returns('q')
125
+ @highline.expects(:agree).with("Really quit? You have unsaved changes! [yn] ").returns(false)
126
+ assert_equal nil, @console.menu(:group => @top_group, :at_top => true, :dirty => true)
127
+ end
128
+
129
+ test "select save from menu" do
130
+ @highline.expects(:say).with("=== Keyrack Main Menu ===")
131
+ @highline.expects(:say).with("1. Twitter [tweeb]")
132
+ @highline.expects(:say).with("2. Google [catfan]")
133
+ @highline.expects(:say).with("3. Google [dogfan]")
134
+ @highline.expects(:say).with("Mode: copy")
135
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [s]ave [m]ode [q]uit")
136
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 2 3 e g s}) }).returns('s')
137
+ assert_equal :save, @console.menu(:group => @top_group, :at_top => true, :dirty => true)
138
+ end
139
+
140
+ test "select group from menu" do
141
+ @top_group.stubs(:group_names).returns(["Blargh"])
142
+ blargh = stub('Blargh group')
143
+ @top_group.stubs(:group).with('Blargh').returns(blargh)
144
+
145
+ @highline.stubs(:color).with('Blargh', instance_of(Symbol)).
146
+ returns('Blargh')
147
+ @highline.expects(:say).with("=== Keyrack Main Menu ===")
148
+ @highline.expects(:say).with("1. Blargh")
149
+ @highline.expects(:say).with("2. Twitter [tweeb]")
150
+ @highline.expects(:say).with("3. Google [catfan]")
151
+ @highline.expects(:say).with("4. Google [dogfan]")
152
+ @highline.expects(:say).with("Mode: copy")
153
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [m]ode [q]uit")
154
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 2 3 4 e g}) }).returns('1')
155
+ assert_equal({:group => blargh}, @console.menu(:group => @top_group, :at_top => true))
156
+ end
157
+
158
+ test "select entry from group menu" do
159
+ facebook = stub('Facebook site', {
160
+ :name => 'Facebook',
161
+ :username => 'username',
162
+ :password => 'password'
163
+ })
164
+ foo_group = stub('Foo group', {
165
+ :name => 'Foo',
166
+ :sites => [facebook],
167
+ :group_names => []
168
+ })
169
+
170
+ @highline.expects(:color).with("Foo", instance_of(Symbol)).
171
+ returns("Foo")
172
+ @highline.expects(:say).with("======== Foo =========")
173
+ @highline.expects(:say).with("1. Facebook [username]")
174
+ @highline.expects(:say).with("Mode: copy")
175
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [t]op [m]ode [q]uit")
176
+
177
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 e g t}) }).returns('1')
178
+ Clipboard.expects(:copy).with('password')
179
+ @highline.expects(:say).with("The password has been copied to your clipboard.")
180
+ assert_nil @console.menu(:group => foo_group, :at_top => false)
181
+ end
182
+
183
+ test "get password" do
184
+ question = mock('question')
185
+ question.expects(:echo=).with(false)
186
+ @highline.expects(:ask).with("Keyrack password: ").yields(question).returns("foobar")
187
+ assert_equal "foobar", @console.get_password
188
+ end
189
+
190
+ test "get new entry with manual password" do
191
+ seq = sequence("new entry")
192
+ @highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
193
+ @highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
194
+ @highline.expects(:ask).with("Generate password? [ync] ").returns("n").in_sequence(seq)
195
+ @highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
196
+ @highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("bar").in_sequence(seq)
197
+ @highline.expects(:say).with("Passwords didn't match. Try again!").in_sequence(seq)
198
+ @highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
199
+ @highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
200
+ assert_equal({:site => "Foo", :username => "bar", :password => "baz"}, @console.get_new_entry)
201
+ end
202
+
203
+ test "get new entry with generated password" do
204
+ seq = sequence("new entry")
205
+ @highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
206
+ @highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
207
+ @highline.expects(:ask).with("Generate password? [ync] ").returns("y").in_sequence(seq)
208
+ Keyrack::Utils.expects(:generate_password).returns('foobar').in_sequence(seq)
209
+ @highline.expects(:color).with('foobar', instance_of(Symbol)).
210
+ returns('foobar').in_sequence(seq)
211
+ @highline.expects(:ask).with("Generated foobar. Sound good? [ync] ").returns("n").in_sequence(seq)
212
+ Keyrack::Utils.expects(:generate_password).returns('foobar').in_sequence(seq)
213
+ @highline.expects(:color).with('foobar', instance_of(Symbol)).
214
+ returns('foobar').in_sequence(seq)
215
+ @highline.expects(:ask).with("Generated foobar. Sound good? [ync] ").returns("y").in_sequence(seq)
216
+ assert_equal({:site => "Foo", :username => "bar", :password => "foobar"}, @console.get_new_entry)
217
+ end
218
+
219
+ test "get new entry with cancel" do
220
+ seq = sequence("new entry")
221
+ @highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
222
+ @highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
223
+
224
+ question = mock('question')
225
+ question.expects(:in=).with(%w{y n c})
226
+ @highline.expects(:ask).with("Generate password? [ync] ").yields(question).returns('c').in_sequence(seq)
227
+ assert_nil @console.get_new_entry
228
+ end
229
+
230
+ test "get new entry with generated password cancel" do
231
+ seq = sequence("new entry")
232
+ @highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
233
+ @highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
234
+ @highline.expects(:ask).with("Generate password? [ync] ").returns("y").in_sequence(seq)
235
+ Keyrack::Utils.expects(:generate_password).returns('foobar').in_sequence(seq)
236
+ @highline.expects(:color).with('foobar', instance_of(Symbol)).
237
+ returns('foobar').in_sequence(seq)
238
+ @highline.expects(:ask).with("Generated foobar. Sound good? [ync] ").returns('c').in_sequence(seq)
239
+ @highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
240
+ @highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
241
+ assert_equal({:site => "Foo", :username => "bar", :password => "baz"}, @console.get_new_entry)
242
+ end
243
+
244
+ test "display first time notice" do
245
+ @highline.expects(:say).with("This looks like your first time using Keyrack. I'll need to ask you a few questions first.")
246
+ @console.display_first_time_notice
247
+ end
248
+
249
+ test "password setup" do
250
+ seq = sequence("password setup")
251
+ @highline.expects(:ask).with("New passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
252
+ @highline.expects(:ask).with("Confirm passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('small').in_sequence(seq)
253
+ @highline.expects(:say).with("Passphrases didn't match.").in_sequence(seq)
254
+ @highline.expects(:ask).with("New passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
255
+ @highline.expects(:ask).with("Confirm passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
256
+ assert_equal 'huge', @console.password_setup
257
+ end
258
+
259
+ test "store setup for filesystem" do
260
+ @highline.expects(:choose).yields(mock {
261
+ expects(:header=).with("Choose storage type")
262
+ expects(:choices).with("filesystem", "ssh")
263
+ }).returns("filesystem")
264
+
265
+ expected = {'type' => 'filesystem', 'path' => 'database'}
266
+ assert_equal expected, @console.store_setup
267
+ end
268
+
269
+ test "store setup for ssh" do
270
+ seq = sequence("store setup")
271
+ @highline.expects(:choose).yields(mock {
272
+ expects(:header=).with("Choose storage type")
273
+ expects(:choices).with("filesystem", "ssh")
274
+ }).returns("ssh").in_sequence(seq)
275
+ @highline.expects(:ask).with("Host: ").returns("example.com").in_sequence(seq)
276
+ @highline.expects(:ask).with("User: ").returns("dudeguy").in_sequence(seq)
277
+ @highline.expects(:ask).with("Remote path: ").returns(".keyrack/database").in_sequence(seq)
278
+
279
+ expected = {'type' => 'ssh', 'host' => 'example.com', 'user' => 'dudeguy', 'path' => '.keyrack/database'}
280
+ assert_equal expected, @console.store_setup
281
+ end
282
+
283
+ test "get new group" do
284
+ @highline.expects(:ask).with("Group: ").yields(mock {
285
+ expects(:validate=).with(/^\w[\w\s]*$/)
286
+ }).returns("Foo")
287
+ assert_equal('Foo', @console.get_new_group)
288
+ end
289
+
290
+ test "choose entry to edit" do
291
+ seq = SequenceHelper.new("editing")
292
+ @highline.expects(:color).with("Choose entry", instance_of(Symbol)).returns("Choose entry")
293
+ seq << @highline.expects(:say).with('=== Choose entry ===')
294
+ seq << @highline.expects(:say).with("1. Twitter [tweeb]")
295
+ seq << @highline.expects(:say).with("2. Google [catfan]")
296
+ seq << @highline.expects(:say).with("3. Google [dogfan]")
297
+ seq << @highline.expects(:say).with("c. Cancel")
298
+ seq << @highline.expects(:ask).yields(mock { expects(:in=).with(%w{c 1 2 3}) }).returns('1')
299
+ assert_equal({:site => @twitter}, @console.choose_entry_to_edit(@top_group))
300
+ end
301
+
302
+ test "choose group to edit" do
303
+ seq = SequenceHelper.new("editing")
304
+ @top_group.expects(:group_names).returns(%w{Foo})
305
+ @highline.expects(:color).with("Choose entry", instance_of(Symbol)).
306
+ returns("Choose entry")
307
+ @highline.expects(:color).with("Foo", instance_of(Symbol)).
308
+ returns("Foo")
309
+ seq << @highline.expects(:say).with('=== Choose entry ===')
310
+ seq << @highline.expects(:say).with("1. Foo")
311
+ seq << @highline.expects(:say).with("2. Twitter [tweeb]")
312
+ seq << @highline.expects(:say).with("3. Google [catfan]")
313
+ seq << @highline.expects(:say).with("4. Google [dogfan]")
314
+ seq << @highline.expects(:say).with("c. Cancel")
315
+ seq << @highline.expects(:ask).yields(mock { expects(:in=).with(%w{c 1 2 3 4}) }).returns('1')
316
+ assert_equal({:group => "Foo"}, @console.choose_entry_to_edit(@top_group))
317
+ end
318
+
319
+ test "choose entry to edit with cancel" do
320
+ seq = SequenceHelper.new("editing")
321
+ @highline.expects(:color).with("Choose entry", instance_of(Symbol)).returns("Choose entry")
322
+ seq << @highline.expects(:say).with('=== Choose entry ===')
323
+ seq << @highline.expects(:say).with("1. Twitter [tweeb]")
324
+ seq << @highline.expects(:say).with("2. Google [catfan]")
325
+ seq << @highline.expects(:say).with("3. Google [dogfan]")
326
+ seq << @highline.expects(:say).with("c. Cancel")
327
+ seq << @highline.expects(:ask).yields(mock { expects(:in=).with(%w{c 1 2 3}) }).returns('c')
328
+ assert_nil @console.choose_entry_to_edit(@top_group)
329
+ end
330
+
331
+ test "selecting username from edit menu" do
332
+ seq = sequence("editing")
333
+
334
+ @highline.expects(:color).with("Twitter [tweeb]", instance_of(Symbol)).
335
+ returns("Twitter [tweeb]")
336
+ @highline.expects(:say).with("Editing entry: Twitter [tweeb]").in_sequence(seq)
337
+ @highline.expects(:say).with("u. Change username").in_sequence(seq)
338
+ @highline.expects(:say).with("p. Change password").in_sequence(seq)
339
+ @highline.expects(:say).with("d. Delete").in_sequence(seq)
340
+ @highline.expects(:say).with("c. Cancel").in_sequence(seq)
341
+ @highline.expects(:ask).yields(mock {
342
+ expects(:in=).with(%w{u p d c})
343
+ }).returns('u').in_sequence(seq)
344
+
345
+ actual = @console.edit_entry(@twitter)
346
+ assert_equal :change_username, actual
347
+ end
348
+
349
+ test "selecting password from edit menu" do
350
+ seq = sequence("editing")
351
+
352
+ @highline.expects(:color).with("Twitter [tweeb]", instance_of(Symbol)).
353
+ returns("Twitter [tweeb]")
354
+ @highline.expects(:say).with("Editing entry: Twitter [tweeb]").in_sequence(seq)
355
+ @highline.expects(:say).with("u. Change username").in_sequence(seq)
356
+ @highline.expects(:say).with("p. Change password").in_sequence(seq)
357
+ @highline.expects(:say).with("d. Delete").in_sequence(seq)
358
+ @highline.expects(:say).with("c. Cancel").in_sequence(seq)
359
+ @highline.expects(:ask).yields(mock {
360
+ expects(:in=).with(%w{u p d c})
361
+ }).returns('p').in_sequence(seq)
362
+
363
+ actual = @console.edit_entry(@twitter)
364
+ assert_equal :change_password, actual
365
+ end
366
+
367
+ test "selecting delete from edit menu" do
368
+ seq = sequence("editing")
369
+
370
+ @highline.expects(:color).with("Twitter [tweeb]", instance_of(Symbol)).
371
+ returns("Twitter [tweeb]")
372
+ @highline.expects(:say).with("Editing entry: Twitter [tweeb]").in_sequence(seq)
373
+ @highline.expects(:say).with("u. Change username").in_sequence(seq)
374
+ @highline.expects(:say).with("p. Change password").in_sequence(seq)
375
+ @highline.expects(:say).with("d. Delete").in_sequence(seq)
376
+ @highline.expects(:say).with("c. Cancel").in_sequence(seq)
377
+ @highline.expects(:ask).yields(mock {
378
+ expects(:in=).with(%w{u p d c})
379
+ }).returns('d').in_sequence(seq)
380
+
381
+ actual = @console.edit_entry(@twitter)
382
+ assert_equal :delete, actual
383
+ end
384
+
385
+ test "cancel edit selection" do
386
+ seq = sequence("editing")
387
+
388
+ @highline.expects(:color).with("Twitter [tweeb]", instance_of(Symbol)).
389
+ returns("Twitter [tweeb]")
390
+ @highline.expects(:say).with("Editing entry: Twitter [tweeb]").in_sequence(seq)
391
+ @highline.expects(:say).with("u. Change username").in_sequence(seq)
392
+ @highline.expects(:say).with("p. Change password").in_sequence(seq)
393
+ @highline.expects(:say).with("d. Delete").in_sequence(seq)
394
+ @highline.expects(:say).with("c. Cancel").in_sequence(seq)
395
+ @highline.expects(:ask).yields(mock {
396
+ expects(:in=).with(%w{u p d c})
397
+ }).returns('c').in_sequence(seq)
398
+
399
+ assert_nil @console.edit_entry(@twitter)
400
+ end
401
+
402
+ test "changing username" do
403
+ seq = SequenceHelper.new("changing username")
404
+ @highline.expects(:color).with("username", instance_of(Symbol)).returns("username")
405
+ seq << @highline.expects(:say).with("Current username: username")
406
+ seq << @highline.expects(:ask).with("New username (blank to cancel): ").returns("foo")
407
+ assert_equal "foo", @console.change_username('username')
408
+ end
409
+
410
+ test "switching mode from menu" do
411
+ @console.mode = :copy
412
+
413
+ @highline.expects(:say).with("=== Keyrack Main Menu ===")
414
+ @highline.expects(:say).with("1. Twitter [tweeb]")
415
+ @highline.expects(:say).with("2. Google [catfan]")
416
+ @highline.expects(:say).with("3. Google [dogfan]")
417
+ @highline.expects(:say).with("Mode: copy")
418
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [m]ode [q]uit")
419
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 2 3 e g}) }).returns('m')
420
+ assert_nil @console.menu(:group => @top_group, :at_top => true)
421
+ assert_equal :print, @console.mode
422
+ end
423
+
424
+ test "confirm overwrite entry" do
425
+ @highline.expects(:color).with("Twitter [tweeb]", instance_of(Symbol)).
426
+ returns("Twitter [tweeb]")
427
+ @highline.expects(:agree).with("There's already an entry for: Twitter [tweeb]. Do you want to overwrite it? [yn] ").returns(true)
428
+ assert_equal true, @console.confirm_overwrite_entry(@twitter)
429
+ end
430
+
431
+ test "confirm delete entry" do
432
+ @highline.expects(:color).with("Twitter [tweeb]", instance_of(Symbol)).
433
+ returns("Twitter [tweeb]")
434
+ @highline.expects(:agree).with("You're about to delete Twitter [tweeb]. Are you sure? [yn] ").returns(true)
435
+ assert_equal true, @console.confirm_delete_entry(@twitter)
436
+ end
437
+
438
+ test "top command" do
439
+ foo_group = stub('Foo group', :name => 'Foo', :sites => [], :group_names => [])
440
+ @highline.stubs(:color).with('Foo', instance_of(Symbol)).returns('Foo')
441
+ @highline.expects(:say).with("=== Foo ===")
442
+ @highline.expects(:say).with("Mode: copy")
443
+ @highline.expects(:say).with("Commands: [n]ew [g]roup [t]op [m]ode [q]uit")
444
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m g t}) }).returns('t')
445
+ assert_equal :top, @console.menu(:group => foo_group, :at_top => false)
446
+ end
447
+
448
+ test "up command" do
449
+ foo_group = stub('Foo group', :name => 'Foo', :sites => [], :group_names => [])
450
+ @highline.stubs(:color).with('Foo', instance_of(Symbol)).returns('Foo')
451
+ @highline.expects(:say).with("=== Foo ===")
452
+ @highline.expects(:say).with("Mode: copy")
453
+ @highline.expects(:say).with("Commands: [n]ew [g]roup [u]p [t]op [m]ode [q]uit")
454
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m g u t}) }).returns('u')
455
+ assert_equal :up, @console.menu(:group => foo_group, :at_top => false, :enable_up => true)
456
+ end
457
+
458
+ test "invalid password" do
459
+ @highline.expects(:say).with("Invalid password.")
460
+ @console.display_invalid_password_notice
461
+ end
462
+
463
+ test "menu prints two columns" do
464
+ # ========== Keyrack Main Menu =========
465
+ # 1. Twitter [tweeb] 2. Google [catfan]
466
+ # 3. Google [dogfan]
467
+
468
+ HighLine::SystemExtensions.expects(:terminal_size).returns([40, 32])
469
+ seq = sequence('say')
470
+ @highline.expects(:say).with('========= Keyrack Main Menu =========')
471
+ @highline.expects(:say).with("1. Twitter [tweeb] ")
472
+ @highline.expects(:say).with("2. Google [catfan]")
473
+ @highline.expects(:say).with("3. Google [dogfan]")
474
+ @highline.expects(:say).with("Mode: copy")
475
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [m]ode [q]uit")
476
+
477
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 2 3 e g}) }).returns('q')
478
+ assert_equal :quit, @console.menu(:group => @top_group, :at_top => true)
479
+ end
480
+
481
+ test "menu prints three columns" do
482
+ HighLine::SystemExtensions.expects(:terminal_size).returns([80, 32])
483
+ @twitter.stubs(:usernames).returns(%w{foo})
484
+ seq = sequence('say')
485
+ @highline.expects(:say).with('============================ Keyrack Main Menu ============================')
486
+ @highline.expects(:say).with("1. Twitter [tweeb] ")
487
+ @highline.expects(:say).with("2. Google [catfan] ")
488
+ @highline.expects(:say).with("3. Google [dogfan]")
489
+ @highline.expects(:say).with("Mode: copy")
490
+ @highline.expects(:say).with("Commands: [n]ew [e]dit [g]roup [m]ode [q]uit")
491
+
492
+ @highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q m 1 2 3 e g}) }).returns('q')
493
+ assert_equal :quit, @console.menu(:group => @top_group, :at_top => true)
494
+ end
495
+ end