keyrack 0.3.0.pre → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +8 -15
- data/Guardfile +6 -0
- data/LICENSE.txt +4 -2
- data/Rakefile +2 -56
- data/keyrack.gemspec +22 -104
- data/lib/keyrack.rb +9 -1
- data/lib/keyrack/database.rb +64 -98
- data/lib/keyrack/event.rb +13 -0
- data/lib/keyrack/exceptions.rb +4 -0
- data/lib/keyrack/group.rb +225 -0
- data/lib/keyrack/migrator.rb +45 -0
- data/lib/keyrack/runner.rb +98 -44
- data/lib/keyrack/site.rb +92 -0
- data/lib/keyrack/ui/console.rb +234 -95
- data/lib/keyrack/utils.rb +0 -18
- data/lib/keyrack/version.rb +3 -0
- data/test/fixtures/database-3.dat +0 -0
- data/test/helper.rb +11 -1
- data/test/integration/test_interactive_console.rb +139 -0
- data/test/unit/store/test_filesystem.rb +21 -0
- data/test/unit/store/test_ssh.rb +32 -0
- data/test/unit/test_database.rb +201 -0
- data/test/unit/test_event.rb +41 -0
- data/test/unit/test_group.rb +703 -0
- data/test/unit/test_migrator.rb +105 -0
- data/test/unit/test_runner.rb +407 -0
- data/test/unit/test_site.rb +181 -0
- data/test/unit/test_store.rb +13 -0
- data/test/unit/test_utils.rb +8 -0
- data/test/unit/ui/test_console.rb +495 -0
- metadata +98 -94
- data/Gemfile.lock +0 -45
- data/TODO +0 -4
- data/VERSION +0 -1
- data/features/console.feature +0 -103
- data/features/step_definitions/keyrack_steps.rb +0 -61
- data/features/support/env.rb +0 -16
- data/test/fixtures/aes +0 -0
- data/test/fixtures/config.yml +0 -4
- data/test/fixtures/id_rsa +0 -54
- data/test/keyrack/store/test_filesystem.rb +0 -25
- data/test/keyrack/store/test_ssh.rb +0 -36
- data/test/keyrack/test_database.rb +0 -111
- data/test/keyrack/test_runner.rb +0 -111
- data/test/keyrack/test_store.rb +0 -15
- data/test/keyrack/test_utils.rb +0 -41
- 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,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
|