imap-backup 1.0.5 → 1.0.6

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +1 -1
  4. data/Gemfile +0 -1
  5. data/README.md +0 -1
  6. data/Rakefile +4 -9
  7. data/bin/imap-backup +0 -1
  8. data/imap-backup.gemspec +0 -1
  9. data/lib/email/mboxrd/message.rb +31 -32
  10. data/lib/imap/backup.rb +17 -4
  11. data/lib/imap/backup/account/connection.rb +70 -64
  12. data/lib/imap/backup/account/folder.rb +21 -26
  13. data/lib/imap/backup/configuration/account.rb +127 -73
  14. data/lib/imap/backup/configuration/asker.rb +38 -31
  15. data/lib/imap/backup/configuration/connection_tester.rb +9 -14
  16. data/lib/imap/backup/configuration/folder_chooser.rb +43 -48
  17. data/lib/imap/backup/configuration/list.rb +19 -24
  18. data/lib/imap/backup/configuration/setup.rb +56 -51
  19. data/lib/imap/backup/configuration/store.rb +47 -52
  20. data/lib/imap/backup/downloader.rb +11 -14
  21. data/lib/imap/backup/serializer/base.rb +8 -11
  22. data/lib/imap/backup/serializer/directory.rb +36 -41
  23. data/lib/imap/backup/serializer/mbox.rb +83 -88
  24. data/lib/imap/backup/utils.rb +0 -3
  25. data/lib/imap/backup/version.rb +1 -2
  26. data/spec/gather_rspec_coverage.rb +0 -1
  27. data/spec/spec_helper.rb +2 -7
  28. data/spec/unit/account/connection_spec.rb +0 -1
  29. data/spec/unit/account/folder_spec.rb +0 -1
  30. data/spec/unit/configuration/account_spec.rb +207 -136
  31. data/spec/unit/configuration/asker_spec.rb +59 -85
  32. data/spec/unit/configuration/connection_tester_spec.rb +36 -26
  33. data/spec/unit/configuration/folder_chooser_spec.rb +3 -6
  34. data/spec/unit/configuration/list_spec.rb +0 -1
  35. data/spec/unit/configuration/setup_spec.rb +8 -9
  36. data/spec/unit/configuration/store_spec.rb +1 -4
  37. data/spec/unit/downloader_spec.rb +0 -1
  38. data/spec/unit/email/mboxrd/message_spec.rb +0 -1
  39. data/spec/unit/serializer/base_spec.rb +0 -1
  40. data/spec/unit/serializer/directory_spec.rb +0 -1
  41. data/spec/unit/serializer/mbox_spec.rb +0 -1
  42. data/spec/unit/utils_spec.rb +0 -1
  43. 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
- module Backup
7
- class Downloader
8
- def initialize(folder, serializer)
9
- @folder, @serializer = folder, serializer
10
- end
5
+ module Imap::Backup
6
+ class Downloader
7
+ def initialize(folder, serializer)
8
+ @folder, @serializer = folder, serializer
9
+ end
11
10
 
12
- def run
13
- uids = @folder.uids - @serializer.uids
14
- uids.each do |uid|
15
- message = @folder.fetch(uid)
16
- next if message.nil?
17
- @serializer.save(uid, message)
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 Backup
5
- module Serializer
6
- DIRECTORY_PERMISSIONS = 0700
7
- FILE_PERMISSIONS = 0600
8
- class Base
9
- def initialize(path, folder)
10
- @path, @folder = path, folder
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
- module Backup
6
- module Serializer
7
- class Directory < Base
8
- def initialize(path, folder)
9
- super
10
- Imap::Backup::Utils.make_folder(@path, @folder, DIRECTORY_PERMISSIONS)
11
- end
12
-
13
- def uids
14
- return [] if ! File.exist?(directory)
15
-
16
- d = Dir.open(directory)
17
- as_strings = d.map do |file|
18
- file[/^0*(\d+).json$/, 1]
19
- end.compact
20
- as_strings.map(&:to_i).sort
21
- end
22
-
23
- def exist?(uid)
24
- message_filename = filename(uid)
25
- File.exist?(message_filename)
26
- end
27
-
28
- def save(uid, message)
29
- message_filename = filename(uid)
30
- File.open(message_filename, 'w') { |f| f.write message.to_json }
31
- FileUtils.chmod 0600, message_filename
32
- end
33
-
34
- private
35
-
36
- def directory
37
- File.join(@path, @folder)
38
- end
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
- module Backup
7
- module Serializer
8
- class Mbox < Base
9
- def initialize(path, folder)
10
- super
11
- create_containing_directory
12
- assert_files
13
- end
14
-
15
- # TODO: cleanup locks, close file handles
16
-
17
- def uids
18
- return @uids if @uids
19
-
20
- @uids = []
21
- return @uids if not exist?
22
-
23
- CSV.foreach(imap_pathname) do |row|
24
- @uids << row[0]
25
- end
26
- @uids
27
- end
28
-
29
- def save(uid, message)
30
- uid = uid.to_s
31
- return if uids.include?(uid)
32
- message = Email::Mboxrd::Message.new(message['RFC822'])
33
- mbox = imap = nil
34
- begin
35
- mbox = File.open(mbox_pathname, 'ab')
36
- imap = File.open(imap_pathname, 'ab')
37
- mbox.write message.to_s
38
- imap.write uid + "\n"
39
- ensure
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
-
@@ -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
-
@@ -2,8 +2,7 @@ module Imap
2
2
  module Backup
3
3
  MAJOR = 1
4
4
  MINOR = 0
5
- REVISION = 5
5
+ REVISION = 6
6
6
  VERSION = [MAJOR, MINOR, REVISION].map(&:to_s).join('.')
7
7
  end
8
8
  end
9
-
@@ -1,2 +1 @@
1
1
  GATHER_RSPEC_COVERAGE = 1
2
-
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?( GATHER_RSPEC_COVERAGE )
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( File.dirname(__FILE__) + '/../lib/imap/backup' )
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
-
@@ -142,4 +142,3 @@ describe Imap::Backup::Account::Connection do
142
142
  end
143
143
  end
144
144
  end
145
-
@@ -74,4 +74,3 @@ describe Imap::Backup::Account::Folder do
74
74
  end
75
75
  end
76
76
  end
77
-
@@ -2,215 +2,286 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Imap::Backup::Configuration::Account do
5
- include HighLineTestHelpers
6
- include InputOutputTestHelpers
5
+ class MockHighlineMenu
6
+ attr_reader :choices
7
+ attr_accessor :header
7
8
 
8
- def choose_menu_item(item)
9
- @state = :initial
10
- @input.should_receive(:gets) do
11
- case @state
12
- when :initial
13
- @state = :done
14
- "#{item}\n"
15
- when :done
16
- "quit\n"
17
- end
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
- before :each do
23
- @account1_path = '/backup/path'
24
- @account1 = {
25
- :username => 'user@example.com',
26
- :password => 'secret',
27
- :local_path => @account1_path,
28
- :folders => [ { :name => 'my_folder' }, { :name => 'another_folder' } ]
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
- @other_account_path = '/existing/path'
31
- @other_account = {
32
- :username => 'existing@example.com',
33
- :password => 'secret',
34
- :local_path => @other_account_path,
35
- :folders => []
35
+ end
36
+ let(:account1) do
37
+ {
38
+ :username => other_email,
39
+ :local_path => other_existing_path,
36
40
  }
37
- @data = {:accounts => [@account1, @other_account]}
38
- @store = stub('Imap::Backup::Configuration::Store')
39
- @store.stub!(:data => @data)
40
- @input, @output = prepare_highline
41
- subject.stub(:system => nil)
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 { Imap::Backup::Configuration::Account.new(@store, @account1) }
58
+ subject { described_class.new(store, account, highline) }
45
59
 
46
- context 'menu' do
47
- it 'clears the screen' do
48
- subject.should_receive(:system).with('clear')
60
+ context 'preparation' do
61
+ before { subject.run }
49
62
 
50
- subject.run
63
+ it 'clears the screen' do
64
+ expect(subject).to have_received(:system).with('clear')
51
65
  end
52
66
 
53
- it 'should show a menu' do
54
- subject.run
55
-
56
- @output.string.should =~ /modify email/
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
- it 'should show account details in the menu' do
66
- subject.run
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
- @output.string.should =~ /email:\s+user@example.com/
69
- @output.string.should =~ /password:\s+x+/
70
- @output.string.should =~ %r{path:\s+/backup/path}
71
- @output.string.should =~ /folders:\s+my_folder, another_folder/
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
- it 'should indicate that a password is not set' do
75
- @account1[:password] = ''
109
+ context 'with no password' do
110
+ let(:existing_password) { '' }
76
111
 
77
- subject.run
112
+ before { subject.run }
78
113
 
79
- @output.string.should =~ /password:\s+\(unset\)/
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
- it 'should modify the email address' do
86
- Imap::Backup::Configuration::Asker.should_receive(:email).once.and_return('new@example.com')
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
- @output.string.should =~ /email:\s+new@example.com/
93
- @account1[:username].should == 'new@example.com'
154
+ it 'modifies the email address' do
155
+ expect(account[:username]).to eq(new_email)
94
156
  end
95
157
 
96
- it 'should do nothing if it creates a duplicate' do
97
- Imap::Backup::Configuration::Asker.should_receive(:email).once.and_return('existing@example.com')
158
+ context 'the email already exists' do
159
+ let(:new_email) { other_email }
98
160
 
99
- choose_menu_item 'modify email'
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
- capturing_output do
102
- subject.run
103
- end.should =~ /there is already an account set up with that email address/i
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
- it 'should update the password' do
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 'should do nothing if the user cancels' do
119
- Imap::Backup::Configuration::Asker.should_receive(:password).once.and_return(nil)
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
- subject.run
184
+ context 'if the user cancels' do
185
+ let(:new_password) { nil }
124
186
 
125
- @account1[:password].should == 'secret'
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 'backup_path' do
130
- it 'should update the path' do
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
- choose_menu_item 'modify backup path'
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
- @account1[:local_path].should == '/new/path'
205
+ it 'updates the server' do
206
+ expect(account[:server]).to eq(server)
141
207
  end
208
+ end
142
209
 
143
- it 'should validate that the path is not used by other backups' do
144
- Imap::Backup::Configuration::Asker.should_receive(:backup_path) do |default, validator|
145
- validator.call(@other_account_path)
146
- '/path'
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
- choose_menu_item 'modify backup path'
223
+ it 'updates the path' do
224
+ expect(account[:local_path]).to eq(new_backup_path)
225
+ end
150
226
 
151
- capturing_output do
152
- subject.run
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
- it 'should add/remove folders' do
158
- @chooser = stub('Imap::Backup::Configuration::FolderChooser')
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
- choose_menu_item 'choose backup folders'
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
- subject.run
241
+ it 'edits folders' do
242
+ expect(chooser).to have_received(:run)
243
+ end
165
244
  end
166
245
 
167
- it 'should allow testing the connection' do
168
- Imap::Backup::Configuration::ConnectionTester.should_receive(:test).with(@account1).and_return('All fine')
169
-
170
- choose_menu_item 'test authentication'
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
- end.should == "All fine\n"
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
- it 'should confirm deletion' do
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 'should delete the account' do
187
- Imap::Backup::Configuration::Setup.highline.stub!(:agree).with("Are you sure? (y/n) ").and_return(true)
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 'should not delete if confirmation is not given' do
197
- Imap::Backup::Configuration::Setup.highline.stub!(:agree).with("Are you sure? (y/n) ").and_return(false)
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
- context 'return to main menu' do
208
- it 'should return' do
209
- @input.stub!(:gets).with().and_return("return\n")
278
+ context 'without confirmation' do
279
+ let(:confirmed) { false }
210
280
 
211
- subject.run.should be_nil
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
-