imap-backup 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+