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.
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
-