imap-backup 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.travis.yml +1 -1
- data/Gemfile +0 -1
- data/README.md +0 -1
- data/Rakefile +4 -9
- data/bin/imap-backup +0 -1
- data/imap-backup.gemspec +0 -1
- data/lib/email/mboxrd/message.rb +31 -32
- data/lib/imap/backup.rb +17 -4
- data/lib/imap/backup/account/connection.rb +70 -64
- data/lib/imap/backup/account/folder.rb +21 -26
- data/lib/imap/backup/configuration/account.rb +127 -73
- data/lib/imap/backup/configuration/asker.rb +38 -31
- data/lib/imap/backup/configuration/connection_tester.rb +9 -14
- data/lib/imap/backup/configuration/folder_chooser.rb +43 -48
- data/lib/imap/backup/configuration/list.rb +19 -24
- data/lib/imap/backup/configuration/setup.rb +56 -51
- data/lib/imap/backup/configuration/store.rb +47 -52
- data/lib/imap/backup/downloader.rb +11 -14
- data/lib/imap/backup/serializer/base.rb +8 -11
- data/lib/imap/backup/serializer/directory.rb +36 -41
- data/lib/imap/backup/serializer/mbox.rb +83 -88
- data/lib/imap/backup/utils.rb +0 -3
- data/lib/imap/backup/version.rb +1 -2
- data/spec/gather_rspec_coverage.rb +0 -1
- data/spec/spec_helper.rb +2 -7
- data/spec/unit/account/connection_spec.rb +0 -1
- data/spec/unit/account/folder_spec.rb +0 -1
- data/spec/unit/configuration/account_spec.rb +207 -136
- data/spec/unit/configuration/asker_spec.rb +59 -85
- data/spec/unit/configuration/connection_tester_spec.rb +36 -26
- data/spec/unit/configuration/folder_chooser_spec.rb +3 -6
- data/spec/unit/configuration/list_spec.rb +0 -1
- data/spec/unit/configuration/setup_spec.rb +8 -9
- data/spec/unit/configuration/store_spec.rb +1 -4
- data/spec/unit/downloader_spec.rb +0 -1
- data/spec/unit/email/mboxrd/message_spec.rb +0 -1
- data/spec/unit/serializer/base_spec.rb +0 -1
- data/spec/unit/serializer/directory_spec.rb +0 -1
- data/spec/unit/serializer/mbox_spec.rb +0 -1
- data/spec/unit/utils_spec.rb +0 -1
- metadata +2 -2
@@ -2,22 +2,19 @@
|
|
2
2
|
require 'rubygems' if RUBY_VERSION < '1.9'
|
3
3
|
require 'json'
|
4
4
|
|
5
|
-
module Imap
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
5
|
+
module Imap::Backup
|
6
|
+
class Downloader
|
7
|
+
def initialize(folder, serializer)
|
8
|
+
@folder, @serializer = folder, serializer
|
9
|
+
end
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
11
|
+
def run
|
12
|
+
uids = @folder.uids - @serializer.uids
|
13
|
+
uids.each do |uid|
|
14
|
+
message = @folder.fetch(uid)
|
15
|
+
next if message.nil?
|
16
|
+
@serializer.save(uid, message)
|
19
17
|
end
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
23
|
-
|
@@ -1,17 +1,14 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
module Imap
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
Imap::Backup::Utils.check_permissions(@path, DIRECTORY_PERMISSIONS)
|
12
|
-
end
|
3
|
+
module Imap::Backup
|
4
|
+
module Serializer
|
5
|
+
DIRECTORY_PERMISSIONS = 0700
|
6
|
+
FILE_PERMISSIONS = 0600
|
7
|
+
class Base
|
8
|
+
def initialize(path, folder)
|
9
|
+
@path, @folder = path, folder
|
10
|
+
Imap::Backup::Utils.check_permissions(@path, DIRECTORY_PERMISSIONS)
|
13
11
|
end
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
17
|
-
|
@@ -1,47 +1,42 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'fileutils'
|
3
3
|
|
4
|
-
module Imap
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def filename(uid)
|
41
|
-
"#{directory}/%012u.json" % uid.to_i
|
42
|
-
end
|
43
|
-
end
|
4
|
+
module Imap::Backup::Serializer
|
5
|
+
class Directory < Base
|
6
|
+
def initialize(path, folder)
|
7
|
+
super
|
8
|
+
Imap::Backup::Utils.make_folder(@path, @folder, DIRECTORY_PERMISSIONS)
|
9
|
+
end
|
10
|
+
|
11
|
+
def uids
|
12
|
+
return [] if ! File.exist?(directory)
|
13
|
+
|
14
|
+
d = Dir.open(directory)
|
15
|
+
as_strings = d.map do |file|
|
16
|
+
file[/^0*(\d+).json$/, 1]
|
17
|
+
end.compact
|
18
|
+
as_strings.map(&:to_i).sort
|
19
|
+
end
|
20
|
+
|
21
|
+
def exist?(uid)
|
22
|
+
message_filename = filename(uid)
|
23
|
+
File.exist?(message_filename)
|
24
|
+
end
|
25
|
+
|
26
|
+
def save(uid, message)
|
27
|
+
message_filename = filename(uid)
|
28
|
+
File.open(message_filename, 'w') { |f| f.write message.to_json }
|
29
|
+
FileUtils.chmod 0600, message_filename
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def directory
|
35
|
+
File.join(@path, @folder)
|
36
|
+
end
|
37
|
+
|
38
|
+
def filename(uid)
|
39
|
+
"#{directory}/%012u.json" % uid.to_i
|
44
40
|
end
|
45
41
|
end
|
46
42
|
end
|
47
|
-
|
@@ -2,95 +2,90 @@
|
|
2
2
|
require 'csv'
|
3
3
|
require 'email/mboxrd/message'
|
4
4
|
|
5
|
-
module Imap
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
mbox.close if mbox
|
41
|
-
imap.close if imap
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def assert_files
|
48
|
-
mbox = mbox_exist?
|
49
|
-
imap = imap_exist?
|
50
|
-
raise '.imap file missing' if mbox and not imap
|
51
|
-
raise '.mbox file missing' if imap and not mbox
|
52
|
-
end
|
53
|
-
|
54
|
-
def create_containing_directory
|
55
|
-
mbox_relative_path = File.dirname(mbox_relative_pathname)
|
56
|
-
return if mbox_relative_path == '.'
|
57
|
-
Imap::Backup::Utils.make_folder(@path, mbox_relative_path, DIRECTORY_PERMISSIONS)
|
58
|
-
end
|
59
|
-
|
60
|
-
def exist?
|
61
|
-
mbox_exist? and imap_exist?
|
62
|
-
end
|
63
|
-
|
64
|
-
def mbox_exist?
|
65
|
-
File.exist?(mbox_pathname)
|
66
|
-
end
|
67
|
-
|
68
|
-
def imap_exist?
|
69
|
-
File.exist?(imap_pathname)
|
70
|
-
end
|
71
|
-
|
72
|
-
def mbox_relative_pathname
|
73
|
-
@folder + '.mbox'
|
74
|
-
end
|
75
|
-
|
76
|
-
def mbox_pathname
|
77
|
-
File.join(@path, mbox_relative_pathname)
|
78
|
-
end
|
79
|
-
|
80
|
-
def imap_pathname
|
81
|
-
filename = @folder + '.imap'
|
82
|
-
File.join(@path, filename)
|
83
|
-
end
|
84
|
-
|
85
|
-
def lock
|
86
|
-
# lock mbox and imap files
|
87
|
-
# create both empty if missing
|
88
|
-
end
|
89
|
-
|
90
|
-
def unlock
|
91
|
-
end
|
5
|
+
module Imap::Backup::Serializer
|
6
|
+
class Mbox < Base
|
7
|
+
def initialize(path, folder)
|
8
|
+
super
|
9
|
+
create_containing_directory
|
10
|
+
assert_files
|
11
|
+
end
|
12
|
+
|
13
|
+
# TODO: cleanup locks, close file handles
|
14
|
+
|
15
|
+
def uids
|
16
|
+
return @uids if @uids
|
17
|
+
|
18
|
+
@uids = []
|
19
|
+
return @uids if not exist?
|
20
|
+
|
21
|
+
CSV.foreach(imap_pathname) do |row|
|
22
|
+
@uids << row[0]
|
23
|
+
end
|
24
|
+
@uids
|
25
|
+
end
|
26
|
+
|
27
|
+
def save(uid, message)
|
28
|
+
uid = uid.to_s
|
29
|
+
return if uids.include?(uid)
|
30
|
+
message = Email::Mboxrd::Message.new(message['RFC822'])
|
31
|
+
mbox = imap = nil
|
32
|
+
begin
|
33
|
+
mbox = File.open(mbox_pathname, 'ab')
|
34
|
+
imap = File.open(imap_pathname, 'ab')
|
35
|
+
mbox.write message.to_s
|
36
|
+
imap.write uid + "\n"
|
37
|
+
ensure
|
38
|
+
mbox.close if mbox
|
39
|
+
imap.close if imap
|
92
40
|
end
|
93
41
|
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def assert_files
|
46
|
+
mbox = mbox_exist?
|
47
|
+
imap = imap_exist?
|
48
|
+
raise '.imap file missing' if mbox and not imap
|
49
|
+
raise '.mbox file missing' if imap and not mbox
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_containing_directory
|
53
|
+
mbox_relative_path = File.dirname(mbox_relative_pathname)
|
54
|
+
return if mbox_relative_path == '.'
|
55
|
+
Imap::Backup::Utils.make_folder(@path, mbox_relative_path, DIRECTORY_PERMISSIONS)
|
56
|
+
end
|
57
|
+
|
58
|
+
def exist?
|
59
|
+
mbox_exist? and imap_exist?
|
60
|
+
end
|
61
|
+
|
62
|
+
def mbox_exist?
|
63
|
+
File.exist?(mbox_pathname)
|
64
|
+
end
|
65
|
+
|
66
|
+
def imap_exist?
|
67
|
+
File.exist?(imap_pathname)
|
68
|
+
end
|
69
|
+
|
70
|
+
def mbox_relative_pathname
|
71
|
+
@folder + '.mbox'
|
72
|
+
end
|
73
|
+
|
74
|
+
def mbox_pathname
|
75
|
+
File.join(@path, mbox_relative_pathname)
|
76
|
+
end
|
77
|
+
|
78
|
+
def imap_pathname
|
79
|
+
filename = @folder + '.imap'
|
80
|
+
File.join(@path, filename)
|
81
|
+
end
|
82
|
+
|
83
|
+
def lock
|
84
|
+
# lock mbox and imap files
|
85
|
+
# create both empty if missing
|
86
|
+
end
|
87
|
+
|
88
|
+
def unlock
|
89
|
+
end
|
94
90
|
end
|
95
91
|
end
|
96
|
-
|
data/lib/imap/backup/utils.rb
CHANGED
@@ -4,7 +4,6 @@ require 'fileutils'
|
|
4
4
|
module Imap
|
5
5
|
module Backup
|
6
6
|
module Utils
|
7
|
-
|
8
7
|
def self.check_permissions(filename, limit)
|
9
8
|
actual = stat(filename)
|
10
9
|
mask = ~limit & 0777
|
@@ -37,8 +36,6 @@ module Imap
|
|
37
36
|
def self.oct(permissions)
|
38
37
|
"0%o" % permissions
|
39
38
|
end
|
40
|
-
|
41
39
|
end
|
42
40
|
end
|
43
41
|
end
|
44
|
-
|
data/lib/imap/backup/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -4,7 +4,7 @@ if RUBY_VERSION < '1.9'
|
|
4
4
|
require 'rspec/autorun'
|
5
5
|
else
|
6
6
|
require 'simplecov'
|
7
|
-
if defined?(
|
7
|
+
if defined?(GATHER_RSPEC_COVERAGE)
|
8
8
|
SimpleCov.start do
|
9
9
|
add_filter "/spec/"
|
10
10
|
add_filter "/vendor/"
|
@@ -12,10 +12,9 @@ else
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
require File.expand_path(
|
15
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/imap/backup')
|
16
16
|
|
17
17
|
module HighLineTestHelpers
|
18
|
-
|
19
18
|
def prepare_highline
|
20
19
|
@input = stub('stdin', :eof? => false)
|
21
20
|
# default gets stub
|
@@ -24,11 +23,9 @@ module HighLineTestHelpers
|
|
24
23
|
Imap::Backup::Configuration::Setup.highline = HighLine.new(@input, @output)
|
25
24
|
[@input, @output]
|
26
25
|
end
|
27
|
-
|
28
26
|
end
|
29
27
|
|
30
28
|
module InputOutputTestHelpers
|
31
|
-
|
32
29
|
def capturing_output
|
33
30
|
output = StringIO.new
|
34
31
|
$stdout = output
|
@@ -37,6 +34,4 @@ module InputOutputTestHelpers
|
|
37
34
|
ensure
|
38
35
|
$stdout = STDOUT
|
39
36
|
end
|
40
|
-
|
41
37
|
end
|
42
|
-
|
@@ -2,215 +2,286 @@
|
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
4
|
describe Imap::Backup::Configuration::Account do
|
5
|
-
|
6
|
-
|
5
|
+
class MockHighlineMenu
|
6
|
+
attr_reader :choices
|
7
|
+
attr_accessor :header
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
9
|
+
def initialize
|
10
|
+
@choices = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def choice(name, &block)
|
14
|
+
choices[name] = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def hidden(name, &block)
|
18
|
+
choices[name] = block
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
22
|
context '#run' do
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
:
|
23
|
+
let(:highline) { double('Highline') }
|
24
|
+
let(:menu) { MockHighlineMenu.new }
|
25
|
+
let(:store) { double('Imap::Backup::Configuration::Store', :data => data) }
|
26
|
+
let(:data) { {:accounts => [account, account1]} }
|
27
|
+
let(:account) do
|
28
|
+
{
|
29
|
+
:username => existing_email,
|
30
|
+
:server => existing_server,
|
31
|
+
:local_path => '/backup/path',
|
32
|
+
:folders => [{:name => 'my_folder'}],
|
33
|
+
:password => existing_password,
|
29
34
|
}
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
:
|
34
|
-
:local_path =>
|
35
|
-
:folders => []
|
35
|
+
end
|
36
|
+
let(:account1) do
|
37
|
+
{
|
38
|
+
:username => other_email,
|
39
|
+
:local_path => other_existing_path,
|
36
40
|
}
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
41
|
+
end
|
42
|
+
let(:existing_email) { 'user@example.com' }
|
43
|
+
let(:new_email) { 'foo@example.com' }
|
44
|
+
let(:existing_server) { 'imap.example.com' }
|
45
|
+
let(:existing_password) { 'password' }
|
46
|
+
let(:other_email) { 'other@example.com' }
|
47
|
+
let(:other_existing_path) { '/other/existing/path' }
|
48
|
+
|
49
|
+
before do
|
50
|
+
allow(subject).to receive(:system).and_return(nil)
|
51
|
+
allow(subject).to receive(:puts).and_return(nil)
|
52
|
+
allow(highline).to receive(:choose) do |&block|
|
53
|
+
block.call(menu)
|
54
|
+
throw :done
|
55
|
+
end
|
42
56
|
end
|
43
57
|
|
44
|
-
subject {
|
58
|
+
subject { described_class.new(store, account, highline) }
|
45
59
|
|
46
|
-
context '
|
47
|
-
|
48
|
-
subject.should_receive(:system).with('clear')
|
60
|
+
context 'preparation' do
|
61
|
+
before { subject.run }
|
49
62
|
|
50
|
-
|
63
|
+
it 'clears the screen' do
|
64
|
+
expect(subject).to have_received(:system).with('clear')
|
51
65
|
end
|
52
66
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
@output.string.should =~ /modify password/
|
58
|
-
@output.string.should =~ /modify backup path/
|
59
|
-
@output.string.should =~ /choose backup folders/
|
60
|
-
@output.string.should =~ /test authentication/
|
61
|
-
@output.string.should =~ /delete/
|
62
|
-
@output.string.should =~ /return to main/
|
67
|
+
context 'menu' do
|
68
|
+
it 'shows the menu' do
|
69
|
+
expect(highline).to have_received(:choose)
|
70
|
+
end
|
63
71
|
end
|
72
|
+
end
|
64
73
|
|
65
|
-
|
66
|
-
|
74
|
+
context 'menu' do
|
75
|
+
[
|
76
|
+
'modify email',
|
77
|
+
'modify password',
|
78
|
+
'modify server',
|
79
|
+
'modify backup path',
|
80
|
+
'choose backup folders',
|
81
|
+
'test connection',
|
82
|
+
'delete',
|
83
|
+
'return to main menu',
|
84
|
+
'quit', # TODO: quit is hidden
|
85
|
+
].each do |item|
|
86
|
+
before { subject.run }
|
87
|
+
|
88
|
+
it "has a '#{item}' item" do
|
89
|
+
expect(menu.choices).to include(item)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
67
93
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
94
|
+
context 'account details' do
|
95
|
+
[
|
96
|
+
['email', /email:\s+user@example.com/],
|
97
|
+
['server', /server:\s+imap.example.com/],
|
98
|
+
['password', /password:\s+x+/],
|
99
|
+
['path', %r(path:\s+/backup/path)],
|
100
|
+
['folders', /folders:\s+my_folder/],
|
101
|
+
].each do |attribute, value|
|
102
|
+
before { subject.run }
|
103
|
+
|
104
|
+
it "shows the #{attribute}" do
|
105
|
+
expect(menu.header).to match(value)
|
106
|
+
end
|
72
107
|
end
|
73
108
|
|
74
|
-
|
75
|
-
|
109
|
+
context 'with no password' do
|
110
|
+
let(:existing_password) { '' }
|
76
111
|
|
77
|
-
subject.run
|
112
|
+
before { subject.run }
|
78
113
|
|
79
|
-
|
114
|
+
it 'indicates that a password is not set' do
|
115
|
+
expect(menu.header).to include('password: (unset)')
|
116
|
+
end
|
80
117
|
end
|
81
|
-
|
82
118
|
end
|
83
119
|
|
84
120
|
context 'email' do
|
85
|
-
|
86
|
-
Imap::Backup::Configuration::Asker.
|
87
|
-
|
88
|
-
choose_menu_item 'modify email'
|
89
|
-
|
121
|
+
before do
|
122
|
+
allow(Imap::Backup::Configuration::Asker).to receive(:email).and_return(new_email)
|
90
123
|
subject.run
|
124
|
+
menu.choices['modify email'].call
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'if the server is blank' do
|
128
|
+
[
|
129
|
+
['GMail', 'foo@gmail.com', 'imap.gmail.com'],
|
130
|
+
['Fastmail', 'bar@fastmail.fm', 'mail.messagingengine.com'],
|
131
|
+
].each do |service, email, expected|
|
132
|
+
context service do
|
133
|
+
let(:new_email) { email }
|
134
|
+
|
135
|
+
context 'with nil' do
|
136
|
+
let(:existing_server) { nil }
|
137
|
+
|
138
|
+
it 'sets a default server' do
|
139
|
+
expect(account[:server]).to eq(expected)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'with an empty string' do
|
144
|
+
let(:existing_server) { '' }
|
145
|
+
|
146
|
+
it 'sets a default server' do
|
147
|
+
expect(account[:server]).to eq(expected)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
91
153
|
|
92
|
-
|
93
|
-
|
154
|
+
it 'modifies the email address' do
|
155
|
+
expect(account[:username]).to eq(new_email)
|
94
156
|
end
|
95
157
|
|
96
|
-
|
97
|
-
|
158
|
+
context 'the email already exists' do
|
159
|
+
let(:new_email) { other_email }
|
98
160
|
|
99
|
-
|
161
|
+
it 'indicates the error' do
|
162
|
+
expect(subject).to have_received(:puts).with('There is already an account set up with that email address')
|
163
|
+
end
|
100
164
|
|
101
|
-
|
102
|
-
|
103
|
-
end
|
165
|
+
it "doesn't set the email" do
|
166
|
+
expect(account[:username]).to eq(existing_email)
|
167
|
+
end
|
104
168
|
end
|
105
169
|
end
|
106
170
|
|
107
171
|
context 'password' do
|
108
|
-
|
109
|
-
Imap::Backup::Configuration::Asker.should_receive(:password).once.and_return('new_pwd')
|
110
|
-
|
111
|
-
choose_menu_item 'modify password'
|
172
|
+
let(:new_password) { 'new_password' }
|
112
173
|
|
174
|
+
before do
|
175
|
+
allow(Imap::Backup::Configuration::Asker).to receive(:password).and_return(new_password)
|
113
176
|
subject.run
|
114
|
-
|
115
|
-
@account1[:password].should == 'new_pwd'
|
177
|
+
menu.choices['modify password'].call
|
116
178
|
end
|
117
179
|
|
118
|
-
it '
|
119
|
-
|
120
|
-
|
121
|
-
choose_menu_item 'modify password'
|
180
|
+
it 'updates the password' do
|
181
|
+
expect(account[:password]).to eq(new_password)
|
182
|
+
end
|
122
183
|
|
123
|
-
|
184
|
+
context 'if the user cancels' do
|
185
|
+
let(:new_password) { nil }
|
124
186
|
|
125
|
-
|
187
|
+
it 'does nothing' do
|
188
|
+
expect(account[:password]).to eq(existing_password)
|
189
|
+
end
|
126
190
|
end
|
127
191
|
end
|
128
192
|
|
129
|
-
context '
|
130
|
-
|
131
|
-
Imap::Backup::Configuration::Asker.should_receive(:backup_path).once do |default, validator|
|
132
|
-
validator.call('new/path')
|
133
|
-
'/new/path'
|
134
|
-
end
|
193
|
+
context 'server' do
|
194
|
+
let(:server) { 'server' }
|
135
195
|
|
136
|
-
|
196
|
+
before do
|
197
|
+
allow(highline).to receive(:ask).with('server: ').and_return(server)
|
198
|
+
end
|
137
199
|
|
200
|
+
before do
|
138
201
|
subject.run
|
202
|
+
menu.choices['modify server'].call
|
203
|
+
end
|
139
204
|
|
140
|
-
|
205
|
+
it 'updates the server' do
|
206
|
+
expect(account[:server]).to eq(server)
|
141
207
|
end
|
208
|
+
end
|
142
209
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
210
|
+
context 'backup_path' do
|
211
|
+
let(:new_backup_path) { '/new/path' }
|
212
|
+
|
213
|
+
before do
|
214
|
+
@validator = nil
|
215
|
+
allow(Imap::Backup::Configuration::Asker).to receive(:backup_path) do |path, validator|
|
216
|
+
@validator = validator
|
217
|
+
new_backup_path
|
147
218
|
end
|
219
|
+
subject.run
|
220
|
+
menu.choices['modify backup path'].call
|
221
|
+
end
|
148
222
|
|
149
|
-
|
223
|
+
it 'updates the path' do
|
224
|
+
expect(account[:local_path]).to eq(new_backup_path)
|
225
|
+
end
|
150
226
|
|
151
|
-
|
152
|
-
|
153
|
-
end.should =~ %r{The path '/existing/path' is used to backup the account 'existing@example.com'}
|
227
|
+
it 'validates that the path is not used by other backups' do
|
228
|
+
expect(@validator.call(other_existing_path)).to be_false
|
154
229
|
end
|
155
230
|
end
|
156
231
|
|
157
|
-
|
158
|
-
|
159
|
-
Imap::Backup::Configuration::FolderChooser.should_receive(:new).with(@account1).and_return(@chooser)
|
160
|
-
@chooser.should_receive(:run).with().once
|
232
|
+
context 'folders' do
|
233
|
+
let(:chooser) { double(:run => nil) }
|
161
234
|
|
162
|
-
|
235
|
+
before do
|
236
|
+
allow(Imap::Backup::Configuration::FolderChooser).to receive(:new).and_return(chooser)
|
237
|
+
subject.run
|
238
|
+
menu.choices['choose backup folders'].call
|
239
|
+
end
|
163
240
|
|
164
|
-
|
241
|
+
it 'edits folders' do
|
242
|
+
expect(chooser).to have_received(:run)
|
243
|
+
end
|
165
244
|
end
|
166
245
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
capturing_output do
|
246
|
+
context 'connection test' do
|
247
|
+
before do
|
248
|
+
allow(Imap::Backup::Configuration::ConnectionTester).to receive(:test).and_return('All fine')
|
249
|
+
allow(highline).to receive(:ask)
|
173
250
|
subject.run
|
174
|
-
|
251
|
+
menu.choices['test connection'].call
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'tests the connection' do
|
255
|
+
expect(Imap::Backup::Configuration::ConnectionTester).to have_received(:test).with(account)
|
256
|
+
end
|
175
257
|
end
|
176
258
|
|
177
259
|
context 'deletion' do
|
178
|
-
|
179
|
-
Imap::Backup::Configuration::Setup.highline.should_receive(:agree).with("Are you sure? (y/n) ").and_return(true)
|
180
|
-
|
181
|
-
choose_menu_item 'delete'
|
260
|
+
let(:confirmed) { true }
|
182
261
|
|
262
|
+
before do
|
263
|
+
allow(highline).to receive(:agree).and_return(confirmed)
|
183
264
|
subject.run
|
265
|
+
catch :done do
|
266
|
+
menu.choices['delete'].call
|
267
|
+
end
|
184
268
|
end
|
185
269
|
|
186
|
-
it '
|
187
|
-
|
188
|
-
|
189
|
-
choose_menu_item 'delete'
|
190
|
-
|
191
|
-
subject.run
|
192
|
-
|
193
|
-
@data[:accounts].should_not include(@account1)
|
270
|
+
it 'asks for confirmation' do
|
271
|
+
expect(highline).to have_received(:agree)
|
194
272
|
end
|
195
273
|
|
196
|
-
it '
|
197
|
-
|
198
|
-
|
199
|
-
choose_menu_item 'delete'
|
200
|
-
|
201
|
-
subject.run
|
202
|
-
|
203
|
-
@data[:accounts].should include(@account1)
|
274
|
+
it 'deletes the account' do
|
275
|
+
expect(data[:accounts].find{|a| a[:username] == existing_email}).to be_nil
|
204
276
|
end
|
205
|
-
end
|
206
277
|
|
207
|
-
|
208
|
-
|
209
|
-
@input.stub!(:gets).with().and_return("return\n")
|
278
|
+
context 'without confirmation' do
|
279
|
+
let(:confirmed) { false }
|
210
280
|
|
211
|
-
|
281
|
+
it 'does nothing' do
|
282
|
+
expect(data[:accounts].find{|a| a[:username] == existing_email}).to eq(account)
|
283
|
+
end
|
212
284
|
end
|
213
285
|
end
|
214
286
|
end
|
215
287
|
end
|
216
|
-
|