imap-backup 0.0.3 → 0.0.4

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.
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+ require 'rubygems' if RUBY_VERSION < '1.9'
1
3
  require 'json'
2
4
 
3
5
  module Imap
@@ -6,13 +6,11 @@ module Imap
6
6
  module Serializer
7
7
  class Directory
8
8
 
9
- include Imap::Backup::Utils
10
-
11
9
  def initialize(path, folder)
12
10
  @path, @folder = path, folder
13
11
  permissions = 0700
14
- check_permissions(@path, permissions)
15
- make_folder(@path, @folder, permissions)
12
+ Imap::Backup::Utils.check_permissions(@path, permissions)
13
+ Imap::Backup::Utils.make_folder(@path, @folder, permissions)
16
14
  end
17
15
 
18
16
  def uids
@@ -5,16 +5,22 @@ module Imap
5
5
  module Backup
6
6
  module Utils
7
7
 
8
- def check_permissions(filename, limit)
9
- stat = File.stat(filename)
10
- actual = stat.mode & 0777
8
+ def self.check_permissions(filename, limit)
9
+ actual = stat(filename)
11
10
  mask = ~limit & 0777
12
11
  if actual & mask != 0
13
12
  raise "Permissions on '#{filename}' should be #{oct(limit)}, not #{oct(actual)}"
14
13
  end
15
14
  end
16
15
 
17
- def make_folder(base_path, path, permissions)
16
+ def self.stat(filename)
17
+ return nil unless File.exist?(filename)
18
+
19
+ stat = File.stat(filename)
20
+ stat.mode & 0777
21
+ end
22
+
23
+ def self.make_folder(base_path, path, permissions)
18
24
  parts = path.split('/')
19
25
  return if parts.size == 0
20
26
  full_path = File.join(base_path, path)
@@ -25,7 +31,7 @@ module Imap
25
31
 
26
32
  private
27
33
 
28
- def oct(permissions)
34
+ def self.oct(permissions)
29
35
  "0%o" % permissions
30
36
  end
31
37
 
@@ -2,7 +2,7 @@ module Imap
2
2
  module Backup
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- REVISION = 3
5
+ REVISION = 4
6
6
  VERSION = [ MAJOR, MINOR, REVISION ].map( &:to_s ).join( '.' )
7
7
  end
8
8
  end
data/spec/spec_helper.rb CHANGED
@@ -14,3 +14,29 @@ end
14
14
 
15
15
  require File.expand_path( File.dirname(__FILE__) + '/../lib/imap/backup' )
16
16
 
17
+ module HighLineTestHelpers
18
+
19
+ def prepare_highline
20
+ @input = stub('stdin', :eof? => false)
21
+ # default gets stub
22
+ @input.stub!(:gets).with().and_return("q\n")
23
+ @output = StringIO.new
24
+ Imap::Backup::Configuration::Setup.highline = HighLine.new(@input, @output)
25
+ [@input, @output]
26
+ end
27
+
28
+ end
29
+
30
+ module InputOutputTestHelpers
31
+
32
+ def capturing_output
33
+ output = StringIO.new
34
+ $stdout = output
35
+ yield
36
+ output.string
37
+ ensure
38
+ $stdout = STDOUT
39
+ end
40
+
41
+ end
42
+
@@ -0,0 +1,224 @@
1
+ # encoding: utf-8
2
+ load File.expand_path( '../../spec_helper.rb', File.dirname(__FILE__) )
3
+
4
+ describe Imap::Backup::Configuration::Account do
5
+
6
+ include HighLineTestHelpers
7
+ include InputOutputTestHelpers
8
+
9
+ def choose_menu_item(item)
10
+ @state = :initial
11
+ @input.should_receive(:gets) do
12
+ case @state
13
+ when :initial
14
+ @state = :done
15
+ "#{item}\n"
16
+ when :done
17
+ "quit\n"
18
+ end
19
+ end
20
+ end
21
+
22
+ context '#run' do
23
+
24
+ before :each do
25
+ @account1_path = '/backup/path'
26
+ @account1 = {
27
+ :username => 'user@example.com',
28
+ :password => 'secret',
29
+ :local_path => @account1_path,
30
+ :folders => [ { :name => 'my_folder' }, { :name => 'another_folder' } ]
31
+ }
32
+ @other_account_path = '/existing/path'
33
+ @other_account = {
34
+ :username => 'existing@example.com',
35
+ :password => 'secret',
36
+ :local_path => @other_account_path,
37
+ :folders => []
38
+ }
39
+ @data = {:accounts => [@account1, @other_account]}
40
+ @store = stub('Imap::Backup::Configuration::Store')
41
+ @store.stub!(:data => @data)
42
+ @input, @output = prepare_highline
43
+ end
44
+
45
+ subject { Imap::Backup::Configuration::Account.new(@store, @account1) }
46
+
47
+ context 'menu' do
48
+
49
+ it 'should show a menu' do
50
+ subject.run
51
+
52
+ @output.string.should =~ /modify email/
53
+ @output.string.should =~ /modify password/
54
+ @output.string.should =~ /modify backup path/
55
+ @output.string.should =~ /choose backup folders/
56
+ @output.string.should =~ /test authentication/
57
+ @output.string.should =~ /delete/
58
+ @output.string.should =~ /return to main/
59
+ end
60
+
61
+ it 'should show account details in the menu' do
62
+ subject.run
63
+
64
+ @output.string.should =~ /email:\s+user@example.com/
65
+ @output.string.should =~ /password:\s+x+/
66
+ @output.string.should =~ %r{path:\s+/backup/path}
67
+ @output.string.should =~ /folders:\s+my_folder, another_folder/
68
+ end
69
+
70
+ it 'should indicate that a password is not set' do
71
+ @account1[:password] = ''
72
+
73
+ subject.run
74
+
75
+ @output.string.should =~ /password:\s+\(unset\)/
76
+ end
77
+
78
+ end
79
+
80
+ context 'email' do
81
+
82
+ it 'should modify the email address' do
83
+ Imap::Backup::Configuration::Asker.should_receive(:email).once.and_return('new@example.com')
84
+
85
+ choose_menu_item 'modify email'
86
+
87
+ subject.run
88
+
89
+ @output.string.should =~ /email:\s+new@example.com/
90
+ @account1[:username].should == 'new@example.com'
91
+ end
92
+
93
+ it 'should do nothing if it creates a duplicate' do
94
+ Imap::Backup::Configuration::Asker.should_receive(:email).once.and_return('existing@example.com')
95
+
96
+ choose_menu_item 'modify email'
97
+
98
+ capturing_output do
99
+ subject.run
100
+ end.should =~ /there is already an account set up with that email address/i
101
+ end
102
+
103
+ end
104
+
105
+ context 'password' do
106
+
107
+ it 'should update the password' do
108
+ Imap::Backup::Configuration::Asker.should_receive(:password).once.and_return('new_pwd')
109
+
110
+ choose_menu_item 'modify password'
111
+
112
+ subject.run
113
+
114
+ @account1[:password].should == 'new_pwd'
115
+ end
116
+
117
+ it 'should do nothing if the user cancels' do
118
+ Imap::Backup::Configuration::Asker.should_receive(:password).once.and_return(nil)
119
+
120
+ choose_menu_item 'modify password'
121
+
122
+ subject.run
123
+
124
+ @account1[:password].should == 'secret'
125
+ end
126
+
127
+ end
128
+
129
+ context 'backup_path' do
130
+
131
+ it 'should update the path' do
132
+ Imap::Backup::Configuration::Asker.should_receive(:backup_path).once do |default, validator|
133
+ validator.call('new/path')
134
+ '/new/path'
135
+ end
136
+
137
+ choose_menu_item 'modify backup path'
138
+
139
+ subject.run
140
+
141
+ @account1[:local_path].should == '/new/path'
142
+ end
143
+
144
+ it 'should validate that the path is not used by other backups' do
145
+ Imap::Backup::Configuration::Asker.should_receive(:backup_path) do |default, validator|
146
+ validator.call(@other_account_path)
147
+ '/path'
148
+ end
149
+
150
+ choose_menu_item 'modify backup path'
151
+
152
+ capturing_output do
153
+ subject.run
154
+ end.should =~ %r{The path '/existing/path' is used to backup the account 'existing@example.com'}
155
+ end
156
+
157
+ end
158
+
159
+ it 'should add/remove folders' do
160
+ @chooser = stub('Imap::Backup::Configuration::FolderChooser')
161
+ Imap::Backup::Configuration::FolderChooser.should_receive(:new).with(@account1).and_return(@chooser)
162
+ @chooser.should_receive(:run).with().once
163
+
164
+ choose_menu_item 'choose backup folders'
165
+
166
+ subject.run
167
+ end
168
+
169
+ it 'should allow testing the connection' do
170
+ Imap::Backup::Configuration::ConnectionTester.should_receive(:test).with(@account1).and_return('All fine')
171
+
172
+ choose_menu_item 'test authentication'
173
+
174
+ capturing_output do
175
+ subject.run
176
+ end.should == "All fine\n"
177
+ end
178
+
179
+ context 'deletion' do
180
+
181
+ it 'should confirm deletion' do
182
+ Imap::Backup::Configuration::Setup.highline.should_receive(:agree).with("Are you sure? (y/n) ").and_return(true)
183
+
184
+ choose_menu_item 'delete'
185
+
186
+ subject.run
187
+ end
188
+
189
+ it 'should delete the account' do
190
+ Imap::Backup::Configuration::Setup.highline.stub!(:agree).with("Are you sure? (y/n) ").and_return(true)
191
+
192
+ choose_menu_item 'delete'
193
+
194
+ subject.run
195
+
196
+ @data[:accounts].should_not include(@account1)
197
+ end
198
+
199
+ it 'should not delete if confirmation is not given' do
200
+ Imap::Backup::Configuration::Setup.highline.stub!(:agree).with("Are you sure? (y/n) ").and_return(false)
201
+
202
+ choose_menu_item 'delete'
203
+
204
+ subject.run
205
+
206
+ @data[:accounts].should include(@account1)
207
+ end
208
+
209
+ end
210
+
211
+ context 'return to main menu' do
212
+
213
+ it 'should return' do
214
+ @input.stub!(:gets).with().and_return("return\n")
215
+
216
+ subject.run.should be_nil
217
+ end
218
+
219
+ end
220
+
221
+ end
222
+
223
+ end
224
+
@@ -0,0 +1,122 @@
1
+ # encoding: utf-8
2
+ load File.expand_path( '../../spec_helper.rb', File.dirname(__FILE__) )
3
+
4
+ describe Imap::Backup::Configuration::Asker do
5
+
6
+ context '.email' do
7
+
8
+ it 'should ask for an email' do
9
+ Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/email/)
10
+
11
+ Imap::Backup::Configuration::Asker.email
12
+ end
13
+
14
+ it 'should validate the address' do
15
+ Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/email/) do |&block|
16
+ q = stub('HighLine::Question', :default= => nil,
17
+ :readline= => nil,
18
+ :responses => {})
19
+ q.should_receive(:validate=).with(instance_of(Regexp))
20
+
21
+ block.call q
22
+ end
23
+
24
+ Imap::Backup::Configuration::Asker.email
25
+ end
26
+
27
+ it 'should return the address' do
28
+ Imap::Backup::Configuration::Setup.highline.stub!(:ask).with(/email/).and_return('new@example.com')
29
+
30
+ Imap::Backup::Configuration::Asker.email.should == 'new@example.com'
31
+ end
32
+
33
+ end
34
+
35
+ context '.password' do
36
+
37
+ before :each do
38
+ Imap::Backup::Configuration::Setup.highline.stub!(:ask).with(/^password/).and_return('secret')
39
+ Imap::Backup::Configuration::Setup.highline.stub!(:ask).with(/^repeat password/).and_return('secret')
40
+ end
41
+
42
+ it 'should ask for a password and confirmation' do
43
+ Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/^password/).and_return('secret')
44
+ Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/^repeat password/).and_return('secret')
45
+
46
+ Imap::Backup::Configuration::Asker.password
47
+ end
48
+
49
+ it 'should return the password' do
50
+ Imap::Backup::Configuration::Asker.password.should == 'secret'
51
+ end
52
+
53
+ it "should ask again if the passwords don't match" do
54
+ state = :password1
55
+ Imap::Backup::Configuration::Setup.highline.stub!(:ask) do
56
+ case state
57
+ when :password1
58
+ state = :confirmation1
59
+ 'secret'
60
+ when :confirmation1
61
+ state = :retry?
62
+ 'wrong!!!'
63
+ when :retry?
64
+ state = :password2
65
+ 'y'
66
+ when :password2
67
+ state = :confirmation2
68
+ 'secret'
69
+ when :confirmation2
70
+ 'secret'
71
+ end
72
+ end
73
+
74
+ Imap::Backup::Configuration::Asker.password
75
+ end
76
+
77
+ it 'should return nil if the user cancels' do
78
+ state = :password1
79
+ Imap::Backup::Configuration::Setup.highline.stub!(:ask) do
80
+ case state
81
+ when :password1
82
+ state = :confirmation1
83
+ 'secret'
84
+ when :confirmation1
85
+ state = :retry?
86
+ 'wrong!!!'
87
+ when :retry?
88
+ state = :password2
89
+ 'n'
90
+ end
91
+ end
92
+
93
+ Imap::Backup::Configuration::Asker.password.should be_nil
94
+ end
95
+
96
+ end
97
+
98
+ context '.backup_path' do
99
+
100
+ it 'should ask for a directory' do
101
+ validator = /validator/
102
+ Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/directory/) do |&block|
103
+ q = stub('HighLine::Question', :responses => {}, :readline= => nil)
104
+ q.should_receive(:default=).with('default path')
105
+ q.should_receive(:validate=).with(validator)
106
+
107
+ block.call q
108
+ end
109
+
110
+ Imap::Backup::Configuration::Asker.backup_path('default path', validator)
111
+ end
112
+
113
+ it 'should return the choice' do
114
+ Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/directory/).and_return('/path')
115
+
116
+ Imap::Backup::Configuration::Asker.backup_path('default path', //).should == '/path'
117
+ end
118
+
119
+ end
120
+
121
+ end
122
+