imap-backup 1.2.2 → 1.2.3

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -0
  3. data/Gemfile +1 -1
  4. data/Rakefile +4 -4
  5. data/bin/imap-backup +23 -25
  6. data/imap-backup.gemspec +14 -14
  7. data/lib/email/mboxrd/message.rb +23 -5
  8. data/lib/email/provider.rb +4 -4
  9. data/lib/imap/backup.rb +18 -18
  10. data/lib/imap/backup/account/connection.rb +6 -6
  11. data/lib/imap/backup/account/folder.rb +4 -5
  12. data/lib/imap/backup/configuration/account.rb +20 -22
  13. data/lib/imap/backup/configuration/asker.rb +8 -10
  14. data/lib/imap/backup/configuration/connection_tester.rb +3 -5
  15. data/lib/imap/backup/configuration/folder_chooser.rb +10 -12
  16. data/lib/imap/backup/configuration/list.rb +1 -3
  17. data/lib/imap/backup/configuration/setup.rb +13 -14
  18. data/lib/imap/backup/configuration/store.rb +7 -8
  19. data/lib/imap/backup/downloader.rb +0 -2
  20. data/lib/imap/backup/serializer/base.rb +0 -2
  21. data/lib/imap/backup/serializer/directory.rb +3 -4
  22. data/lib/imap/backup/serializer/mbox.rb +11 -12
  23. data/lib/imap/backup/utils.rb +2 -3
  24. data/lib/imap/backup/version.rb +2 -2
  25. data/spec/spec_helper.rb +6 -6
  26. data/spec/support/higline_test_helpers.rb +1 -1
  27. data/spec/support/shared_examples/account_flagging.rb +6 -6
  28. data/spec/unit/account/connection_spec.rb +50 -51
  29. data/spec/unit/account/folder_spec.rb +18 -19
  30. data/spec/unit/configuration/account_spec.rb +96 -97
  31. data/spec/unit/configuration/asker_spec.rb +33 -34
  32. data/spec/unit/configuration/connection_tester_spec.rb +18 -19
  33. data/spec/unit/configuration/folder_chooser_spec.rb +34 -35
  34. data/spec/unit/configuration/list_spec.rb +13 -14
  35. data/spec/unit/configuration/setup_spec.rb +46 -47
  36. data/spec/unit/configuration/store_spec.rb +56 -57
  37. data/spec/unit/downloader_spec.rb +18 -19
  38. data/spec/unit/email/mboxrd/message_spec.rb +55 -11
  39. data/spec/unit/email/provider_spec.rb +12 -12
  40. data/spec/unit/serializer/base_spec.rb +7 -9
  41. data/spec/unit/serializer/directory_spec.rb +18 -19
  42. data/spec/unit/serializer/mbox_spec.rb +35 -37
  43. data/spec/unit/utils_spec.rb +26 -27
  44. metadata +17 -2
@@ -1,19 +1,18 @@
1
- # encoding: utf-8
2
- require 'spec_helper'
3
- require 'json'
1
+ require "spec_helper"
2
+ require "json"
4
3
 
5
4
  describe Imap::Backup::Configuration::Store do
6
- let(:directory) { '/base/path' }
7
- let(:file_path) { File.join(directory, '/config.json') }
5
+ let(:directory) { "/base/path" }
6
+ let(:file_path) { File.join(directory, "/config.json") }
8
7
  let(:file_exists) { true }
9
8
  let(:directory_exists) { true }
10
- let(:data) { {:debug => debug, :accounts => accounts} }
9
+ let(:data) { {debug: debug, accounts: accounts} }
11
10
  let(:debug) { true }
12
11
  let(:accounts) { [] }
13
12
  let(:configuration) { data.to_json }
14
13
 
15
14
  before do
16
- stub_const('Imap::Backup::Configuration::Store::CONFIGURATION_DIRECTORY', directory)
15
+ stub_const("Imap::Backup::Configuration::Store::CONFIGURATION_DIRECTORY", directory)
17
16
  allow(File).to receive(:directory?).with(directory).and_return(directory_exists)
18
17
  allow(File).to receive(:exist?).with(file_path).and_return(file_exists)
19
18
  allow(Imap::Backup::Utils).to receive(:stat).with(directory).and_return(0700)
@@ -22,9 +21,9 @@ describe Imap::Backup::Configuration::Store do
22
21
  allow(File).to receive(:read).with(file_path).and_return(configuration)
23
22
  end
24
23
 
25
- describe '.exist?' do
24
+ describe ".exist?" do
26
25
  [true, false].each do |exists|
27
- state = exists ? 'exists' : "doesn't exist"
26
+ state = exists ? "exists" : "doesn't exist"
28
27
  context "when the file #{state}" do
29
28
  let(:file_exists) { exists }
30
29
 
@@ -35,123 +34,123 @@ describe Imap::Backup::Configuration::Store do
35
34
  end
36
35
  end
37
36
 
38
- describe '#path' do
39
- it 'is the directory containing the configuration file' do
37
+ describe "#path" do
38
+ it "is the directory containing the configuration file" do
40
39
  expect(subject.path).to eq(directory)
41
40
  end
42
41
  end
43
42
 
44
- describe '#modified?' do
43
+ describe "#modified?" do
45
44
  context "'with accounts flagged 'modified'" do
46
- let(:accounts) { [{:name => 'foo', :modified => true}] }
45
+ let(:accounts) { [{name: "foo", modified: true}] }
47
46
 
48
- it 'is true' do
47
+ it "is true" do
49
48
  expect(subject.modified?).to be_truthy
50
49
  end
51
50
  end
52
51
 
53
52
  context "'with accounts flagged 'delete'" do
54
- let(:accounts) { [{:name => 'foo', :delete => true}] }
53
+ let(:accounts) { [{name: "foo", delete: true}] }
55
54
 
56
- it 'is true' do
55
+ it "is true" do
57
56
  expect(subject.modified?).to be_truthy
58
57
  end
59
58
  end
60
59
 
61
60
  context "without accounts flagged 'modified'" do
62
- let(:accounts) { [{:name => 'foo'}] }
61
+ let(:accounts) { [{name: "foo"}] }
63
62
 
64
- it 'is false' do
63
+ it "is false" do
65
64
  expect(subject.modified?).to be_falsey
66
65
  end
67
66
  end
68
67
  end
69
68
 
70
- describe '#debug?' do
71
- context 'when the debug flag is true' do
72
- it 'is true' do
69
+ describe "#debug?" do
70
+ context "when the debug flag is true" do
71
+ it "is true" do
73
72
  expect(subject.debug?).to be_truthy
74
73
  end
75
74
  end
76
75
 
77
- context 'when the debug flag is false' do
76
+ context "when the debug flag is false" do
78
77
  let(:debug) { false }
79
78
 
80
- it 'is false' do
79
+ it "is false" do
81
80
  expect(subject.debug?).to be_falsey
82
81
  end
83
82
  end
84
83
 
85
- context 'when the debug flag is missing' do
86
- let(:data) { {:accounts => accounts} }
84
+ context "when the debug flag is missing" do
85
+ let(:data) { {accounts: accounts} }
87
86
 
88
- it 'is false' do
87
+ it "is false" do
89
88
  expect(subject.debug?).to be_falsey
90
89
  end
91
90
  end
92
91
 
93
- context 'when the debug flag is neither true nor false' do
94
- let(:debug) { 'hi' }
92
+ context "when the debug flag is neither true nor false" do
93
+ let(:debug) { "hi" }
95
94
 
96
- it 'is false' do
95
+ it "is false" do
97
96
  expect(subject.debug?).to be_falsey
98
97
  end
99
98
  end
100
99
  end
101
100
 
102
- describe '#debug=' do
101
+ describe "#debug=" do
103
102
  before { subject.debug = debug }
104
103
 
105
- context 'when the supplied value is true' do
106
- it 'sets the flag to true' do
104
+ context "when the supplied value is true" do
105
+ it "sets the flag to true" do
107
106
  expect(subject.debug?).to be_truthy
108
107
  end
109
108
  end
110
109
 
111
- context 'when the supplied value is false' do
110
+ context "when the supplied value is false" do
112
111
  let(:debug) { false }
113
112
 
114
- it 'sets the flag to false' do
113
+ it "sets the flag to false" do
115
114
  expect(subject.debug?).to be_falsey
116
115
  end
117
116
  end
118
117
 
119
- context 'when the supplied value is neither true nor false' do
120
- let(:debug) { 'ciao' }
118
+ context "when the supplied value is neither true nor false" do
119
+ let(:debug) { "ciao" }
121
120
 
122
- it 'sets the flag to false' do
121
+ it "sets the flag to false" do
123
122
  expect(subject.debug?).to be_falsey
124
123
  end
125
124
  end
126
125
  end
127
126
 
128
- describe '#save' do
127
+ describe "#save" do
129
128
  let(:directory_exists) { false }
130
- let(:file) { double('File', :write => nil) }
129
+ let(:file) { double("File", write: nil) }
131
130
 
132
131
  before do
133
132
  allow(FileUtils).to receive(:mkdir)
134
133
  allow(FileUtils).to receive(:chmod)
135
- allow(File).to receive(:open).with(file_path, 'w') { |&b| b.call file }
136
- allow(JSON).to receive(:pretty_generate).and_return('JSON output')
134
+ allow(File).to receive(:open).with(file_path, "w") { |&b| b.call file }
135
+ allow(JSON).to receive(:pretty_generate).and_return("JSON output")
137
136
  end
138
137
 
139
138
  subject { described_class.new }
140
139
 
141
- it 'creates the config directory' do
140
+ it "creates the config directory" do
142
141
  subject.save
143
142
 
144
143
  expect(FileUtils).to have_received(:mkdir).with(directory)
145
144
  end
146
145
 
147
- it 'saves the configuration' do
146
+ it "saves the configuration" do
148
147
  subject.save
149
148
 
150
- expect(file).to have_received(:write).with('JSON output')
149
+ expect(file).to have_received(:write).with("JSON output")
151
150
  end
152
151
 
153
- context 'when accounts are modified' do
154
- let(:accounts) { [{:name => 'foo', :modified => true}] }
152
+ context "when accounts are modified" do
153
+ let(:accounts) { [{name: "foo", modified: true}] }
155
154
 
156
155
  before { subject.save }
157
156
 
@@ -163,17 +162,17 @@ describe Imap::Backup::Configuration::Store do
163
162
  end
164
163
  end
165
164
 
166
- context 'when accounts are to be deleted' do
165
+ context "when accounts are to be deleted" do
167
166
  let(:accounts) do
168
167
  [
169
- {:name => 'keep_me'},
170
- {:name => 'delete_me', :delete => true},
168
+ {name: "keep_me"},
169
+ {name: "delete_me", delete: true}
171
170
  ]
172
171
  end
173
172
 
174
173
  before { subject.save }
175
174
 
176
- it 'does not save them' do
175
+ it "does not save them" do
177
176
  expected = Marshal.load(Marshal.dump(data))
178
177
  expected[:accounts].pop
179
178
 
@@ -181,15 +180,15 @@ describe Imap::Backup::Configuration::Store do
181
180
  end
182
181
  end
183
182
 
184
- context 'when file permissions are too open' do
183
+ context "when file permissions are too open" do
185
184
  before { subject.save }
186
185
 
187
- it 'sets them to 0600' do
186
+ it "sets them to 0600" do
188
187
  expect(FileUtils).to have_received(:chmod).with(0600, file_path)
189
188
  end
190
189
  end
191
190
 
192
- context 'if the configuration file is missing' do
191
+ context "if the configuration file is missing" do
193
192
  let(:file_exists) { false }
194
193
 
195
194
  it "doesn't fail" do
@@ -199,17 +198,17 @@ describe Imap::Backup::Configuration::Store do
199
198
  end
200
199
  end
201
200
 
202
- context 'if the config file permissions are too lax' do
201
+ context "if the config file permissions are too lax" do
203
202
  let(:file_exists) { true }
204
203
 
205
204
  before do
206
- allow(Imap::Backup::Utils).to receive(:check_permissions).with(file_path, 0600).and_raise('Error')
205
+ allow(Imap::Backup::Utils).to receive(:check_permissions).with(file_path, 0600).and_raise("Error")
207
206
  end
208
207
 
209
- it 'fails' do
208
+ it "fails" do
210
209
  expect do
211
210
  subject.save
212
- end.to raise_error(RuntimeError, 'Error')
211
+ end.to raise_error(RuntimeError, "Error")
213
212
  end
214
213
  end
215
214
  end
@@ -1,39 +1,38 @@
1
- # encoding: utf-8
2
- require 'spec_helper'
1
+ require "spec_helper"
3
2
 
4
3
  describe Imap::Backup::Downloader do
5
- describe '#run' do
6
- let(:message) { {'RFC822' => 'blah'} }
7
- let(:folder) { double('Imap::Backup::Account::Folder', :fetch => message, :name => 'folder') }
8
- let(:folder_uids) { ['111', '222', '333'] }
9
- let(:serializer) { double('Imap::Backup::Serializer', :save => nil) }
10
- let(:serializer_uids) { ['222'] }
4
+ describe "#run" do
5
+ let(:message) { {"RFC822" => "blah"} }
6
+ let(:folder) { double("Imap::Backup::Account::Folder", fetch: message, name: "folder") }
7
+ let(:folder_uids) { ["111", "222", "333"] }
8
+ let(:serializer) { double("Imap::Backup::Serializer", save: nil) }
9
+ let(:serializer_uids) { ["222"] }
11
10
 
12
11
  subject { described_class.new(folder, serializer) }
13
12
 
14
13
  before do
15
14
  allow(folder).to receive(:uids).and_return(folder_uids)
16
15
  allow(serializer).to receive(:uids).and_return(serializer_uids)
17
- allow(folder).to receive(:fetch).with('333').and_return(nil)
16
+ allow(folder).to receive(:fetch).with("333").and_return(nil)
18
17
  subject.run
19
18
  end
20
19
 
21
- context '#run' do
22
- context 'fetched messages' do
23
- it 'are saved' do
24
- expect(serializer).to have_received(:save).with('111', message)
20
+ context "#run" do
21
+ context "fetched messages" do
22
+ it "are saved" do
23
+ expect(serializer).to have_received(:save).with("111", message)
25
24
  end
26
25
  end
27
26
 
28
- context 'messages which are already present' do
29
- specify 'are skipped' do
30
- expect(serializer).to_not have_received(:save).with('222', anything)
27
+ context "messages which are already present" do
28
+ specify "are skipped" do
29
+ expect(serializer).to_not have_received(:save).with("222", anything)
31
30
  end
32
31
  end
33
32
 
34
- context 'failed fetches' do
35
- specify 'are skipped' do
36
- expect(serializer).to_not have_received(:save).with('333', anything)
33
+ context "failed fetches" do
34
+ specify "are skipped" do
35
+ expect(serializer).to_not have_received(:save).with("333", anything)
37
36
  end
38
37
  end
39
38
  end
@@ -1,32 +1,47 @@
1
- # encoding: utf-8
1
+ require "spec_helper"
2
2
 
3
- require 'spec_helper'
3
+ msg_no_from = %Q|Delivered-To: you@example.com
4
+ From: example <www.example.com>
5
+ To: FirstName LastName <you@example.com>
6
+ Subject: Re: no subject|
7
+
8
+ msg_bad_from = %Q|Delivered-To: you@example.com
9
+ from: "FirstName LastName (TEXT)" <"TEXT*" <no-reply@example.com>>
10
+ To: FirstName LastName <you@example.com>
11
+ Subject: Re: no subject
12
+ Sender: FistName LastName <"TEXT*"no-reply=example.com@example.com>|
13
+
14
+ msg_no_from_but_return_path = %Q|Delivered-To: you@example.com
15
+ From: example <www.example.com>
16
+ To: FirstName LastName <you@example.com>
17
+ Return-Path: <me@example.com>
18
+ Subject: Re: no subject|
4
19
 
5
20
  describe Email::Mboxrd::Message do
6
- let(:from) { 'me@example.com' }
21
+ let(:from) { "me@example.com" }
7
22
  let(:date) { DateTime.new(2012, 12, 13, 18, 23, 45) }
8
23
  let(:message_body) do
9
- double('Body', :clone => cloned_message_body, :force_encoding => nil)
24
+ double("Body", clone: cloned_message_body, force_encoding: nil)
10
25
  end
11
26
  let(:cloned_message_body) { "Foo\nBar\nFrom at the beginning of the line\n>>From quoted" }
12
27
 
13
28
  subject { described_class.new(message_body) }
14
29
 
15
- context '#to_s' do
16
- let(:mail) { double('Mail', :from =>[from], :date => date) }
30
+ context "#to_s" do
31
+ let(:mail) { double("Mail", from: [from], date: date) }
17
32
 
18
33
  before do
19
34
  allow(Mail).to receive(:new).with(cloned_message_body).and_return(mail)
20
35
  end
21
36
 
22
- it 'does not modify the message' do
37
+ it "does not modify the message" do
23
38
  subject.to_s
24
39
 
25
- expect(message_body).to_not have_received(:force_encoding).with('binary')
40
+ expect(message_body).to_not have_received(:force_encoding).with("binary")
26
41
  end
27
42
 
28
43
  it "adds a 'From ' line at the start" do
29
- expect(subject.to_s).to start_with('From ' + from + ' ' + date.asctime + "\n")
44
+ expect(subject.to_s).to start_with("From " + from + " " + date.asctime + "\n")
30
45
  end
31
46
 
32
47
  it "replaces existing 'From ' with '>From '" do
@@ -37,12 +52,41 @@ describe Email::Mboxrd::Message do
37
52
  expect(subject.to_s).to include("\n>>>From quoted")
38
53
  end
39
54
 
40
- context 'when date is missing' do
55
+ context "when date is missing" do
41
56
  let(:date) { nil }
42
57
 
43
- it 'does no fail' do
58
+ it "does no fail" do
44
59
  expect { subject.to_s }.to_not raise_error
45
60
  end
46
61
  end
47
62
  end
63
+
64
+ context '#from' do
65
+ before do
66
+ # call original for these tests because we want to test the behaviour of
67
+ # class-under-test given different behaviour of the Mail parser
68
+ allow(Mail).to receive(:new).and_call_original
69
+ end
70
+
71
+ context "when original message 'from' is nil" do
72
+ let(:message_body) { msg_no_from }
73
+ it "'from' is empty string" do
74
+ expect(subject.to_s).to start_with("From \n")
75
+ end
76
+ end
77
+
78
+ context "when original message 'from' is a string but not an address" do
79
+ let(:message_body) { msg_bad_from }
80
+ it "'from' is empty string" do
81
+ expect(subject.to_s).to start_with("From \n")
82
+ end
83
+ end
84
+
85
+ context "when original message 'from' is nil and 'envelope from' is nil and 'return path' is available" do
86
+ let(:message_body) { msg_no_from_but_return_path }
87
+ it "'return path' is used as 'from'" do
88
+ expect(subject.to_s).to start_with("From " + from + " \n")
89
+ end
90
+ end
91
+ end
48
92
  end
@@ -1,9 +1,9 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  describe Email::Provider do
4
- describe '.for_address' do
5
- context 'known providers' do
6
- [['gmail.com', :gmail], ['fastmail.fm', :fastmail]].each do |domain, provider|
4
+ describe ".for_address" do
5
+ context "known providers" do
6
+ [["gmail.com", :gmail], ["fastmail.fm", :fastmail]].each do |domain, provider|
7
7
  it "recognizes #{provider}" do
8
8
  address = "foo@#{domain}"
9
9
  expect(described_class.for_address(address).provider).to eq(provider)
@@ -11,24 +11,24 @@ describe Email::Provider do
11
11
  end
12
12
  end
13
13
 
14
- context 'with unknown providers' do
15
- it 'returns a default provider' do
16
- expect(described_class.for_address('foo@unknown.com').provider).to eq(:default)
14
+ context "with unknown providers" do
15
+ it "returns a default provider" do
16
+ expect(described_class.for_address("foo@unknown.com").provider).to eq(:default)
17
17
  end
18
18
  end
19
19
  end
20
20
 
21
21
  subject { described_class.new(:gmail) }
22
22
 
23
- describe '#options' do
24
- it 'returns options' do
23
+ describe "#options" do
24
+ it "returns options" do
25
25
  expect(subject.options).to eq(port: 993, ssl: true)
26
26
  end
27
27
  end
28
28
 
29
- describe '#host' do
30
- it 'returns host' do
31
- expect(subject.host).to eq('imap.gmail.com')
29
+ describe "#host" do
30
+ it "returns host" do
31
+ expect(subject.host).to eq("imap.gmail.com")
32
32
  end
33
33
  end
34
34
  end