imap-backup 2.0.0 → 2.1.0

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec-all +2 -0
  3. data/.rubocop.yml +10 -1
  4. data/.travis.yml +1 -0
  5. data/README.md +1 -1
  6. data/Rakefile +0 -1
  7. data/bin/imap-backup +3 -9
  8. data/imap-backup.gemspec +5 -5
  9. data/lib/email/mboxrd/message.rb +2 -2
  10. data/lib/imap/backup/account/connection.rb +11 -3
  11. data/lib/imap/backup/account/folder.rb +11 -6
  12. data/lib/imap/backup/configuration/account.rb +7 -7
  13. data/lib/imap/backup/configuration/asker.rb +2 -1
  14. data/lib/imap/backup/configuration/connection_tester.rb +1 -1
  15. data/lib/imap/backup/configuration/folder_chooser.rb +32 -5
  16. data/lib/imap/backup/configuration/list.rb +2 -0
  17. data/lib/imap/backup/configuration/setup.rb +2 -1
  18. data/lib/imap/backup/configuration/store.rb +3 -6
  19. data/lib/imap/backup/downloader.rb +8 -7
  20. data/lib/imap/backup/serializer/mbox.rb +2 -1
  21. data/lib/imap/backup/serializer/mbox_store.rb +14 -6
  22. data/lib/imap/backup/uploader.rb +1 -0
  23. data/lib/imap/backup/utils.rb +11 -9
  24. data/lib/imap/backup/version.rb +1 -1
  25. data/spec/features/backup_spec.rb +6 -5
  26. data/spec/features/support/backup_directory.rb +5 -5
  27. data/spec/features/support/email_server.rb +11 -8
  28. data/spec/features/support/shared/connection_context.rb +2 -2
  29. data/spec/support/fixtures.rb +1 -1
  30. data/spec/support/higline_test_helpers.rb +1 -1
  31. data/spec/unit/email/mboxrd/message_spec.rb +51 -42
  32. data/spec/unit/email/provider_spec.rb +0 -2
  33. data/spec/unit/imap/backup/account/connection_spec.rb +18 -11
  34. data/spec/unit/imap/backup/account/folder_spec.rb +26 -12
  35. data/spec/unit/imap/backup/configuration/account_spec.rb +22 -19
  36. data/spec/unit/imap/backup/configuration/asker_spec.rb +30 -31
  37. data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +16 -13
  38. data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +45 -18
  39. data/spec/unit/imap/backup/configuration/list_spec.rb +8 -13
  40. data/spec/unit/imap/backup/configuration/setup_spec.rb +36 -30
  41. data/spec/unit/imap/backup/configuration/store_spec.rb +7 -4
  42. data/spec/unit/imap/backup/downloader_spec.rb +11 -7
  43. data/spec/unit/imap/backup/serializer/mbox_spec.rb +2 -5
  44. data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +4 -4
  45. data/spec/unit/imap/backup/uploader_spec.rb +0 -2
  46. data/spec/unit/imap/backup/utils_spec.rb +1 -3
  47. metadata +6 -6
@@ -1,5 +1,3 @@
1
- require "spec_helper"
2
-
3
1
  describe Email::Provider do
4
2
  describe ".for_address" do
5
3
  context "known providers" do
@@ -1,5 +1,3 @@
1
- require "spec_helper"
2
-
3
1
  describe Imap::Backup::Account::Connection do
4
2
  def self.backup_folder
5
3
  "backup_folder"
@@ -9,6 +7,8 @@ describe Imap::Backup::Account::Connection do
9
7
  {name: backup_folder}
10
8
  end
11
9
 
10
+ subject { described_class.new(options) }
11
+
12
12
  let(:imap) do
13
13
  instance_double(Net::IMAP, login: nil, disconnect: nil)
14
14
  end
@@ -18,7 +18,7 @@ describe Imap::Backup::Account::Connection do
18
18
  username: username,
19
19
  password: "password",
20
20
  local_path: local_path,
21
- folders: backup_folders,
21
+ folders: backup_folders
22
22
  }
23
23
  end
24
24
  let(:local_path) { "local_path" }
@@ -48,8 +48,6 @@ describe Imap::Backup::Account::Connection do
48
48
  allow(Imap::Backup::Utils).to receive(:make_folder)
49
49
  end
50
50
 
51
- subject { described_class.new(options) }
52
-
53
51
  shared_examples "connects to IMAP" do
54
52
  it "sets up the IMAP connection" do
55
53
  expect(Net::IMAP).to have_received(:new)
@@ -78,10 +76,10 @@ describe Imap::Backup::Account::Connection do
78
76
  end
79
77
 
80
78
  describe "#imap" do
81
- before { @result = subject.imap }
79
+ let!(:result) { subject.imap }
82
80
 
83
81
  it "returns the IMAP connection" do
84
- expect(@result).to eq(imap)
82
+ expect(result).to eq(imap)
85
83
  end
86
84
 
87
85
  include_examples "connects to IMAP"
@@ -108,7 +106,7 @@ describe Imap::Backup::Account::Connection do
108
106
  allow(Imap::Backup::Serializer::Mbox).to receive(:new) { serializer }
109
107
  end
110
108
 
111
- it "should return the names of folders" do
109
+ it "returns the names of folders" do
112
110
  expect(subject.status[0][:name]).to eq(self.class.backup_folder)
113
111
  end
114
112
 
@@ -116,7 +114,7 @@ describe Imap::Backup::Account::Connection do
116
114
  expect(subject.status[0][:local]).to eq([local_uid])
117
115
  end
118
116
 
119
- it "should retrieve the available uids" do
117
+ it "retrieves the available uids" do
120
118
  expect(subject.status[0][:remote]).to eq([remote_uid])
121
119
  end
122
120
  end
@@ -126,9 +124,11 @@ describe Imap::Backup::Account::Connection do
126
124
  instance_double(
127
125
  Imap::Backup::Account::Folder,
128
126
  name: "folder",
127
+ exist?: exists,
129
128
  uid_validity: uid_validity
130
129
  )
131
130
  end
131
+ let(:exists) { true }
132
132
  let(:uid_validity) { 123 }
133
133
  let(:downloader) { instance_double(Imap::Backup::Downloader, run: nil) }
134
134
 
@@ -143,13 +143,20 @@ describe Imap::Backup::Account::Connection do
143
143
  with(subject, self.class.backup_folder).and_return(folder)
144
144
  allow(Imap::Backup::Serializer::Mbox).to receive(:new).
145
145
  with(local_path, self.class.backup_folder).and_return(serializer)
146
+ subject.run_backup
146
147
  end
147
148
 
148
- before { subject.run_backup }
149
-
150
149
  it "runs the downloader" do
151
150
  expect(downloader).to have_received(:run)
152
151
  end
152
+
153
+ context "when a folder does not exist" do
154
+ let(:exists) { false }
155
+
156
+ it "does not run the downloader" do
157
+ expect(downloader).to_not have_received(:run)
158
+ end
159
+ end
153
160
  end
154
161
 
155
162
  context "without supplied backup_folders" do
@@ -1,6 +1,8 @@
1
- require "spec_helper"
1
+ # rubocop:disable RSpec/PredicateMatcher
2
2
 
3
3
  describe Imap::Backup::Account::Folder do
4
+ subject { described_class.new(connection, "my_folder") }
5
+
4
6
  let(:imap) do
5
7
  instance_double(
6
8
  Net::IMAP,
@@ -10,21 +12,19 @@ describe Imap::Backup::Account::Folder do
10
12
  responses: responses
11
13
  )
12
14
  end
13
- let(:connection) { double("Imap::Backup::Account::Connection", imap: imap) }
14
- let(:missing_mailbox_data) do
15
- double("Data", text: "Unknown Mailbox: my_folder")
15
+ let(:connection) do
16
+ instance_double(Imap::Backup::Account::Connection, imap: imap)
16
17
  end
17
- let(:missing_mailbox_response) do
18
- double("Response", data: missing_mailbox_data)
18
+ let(:missing_mailbox_data) do
19
+ OpenStruct.new(text: "Unknown Mailbox: my_folder")
19
20
  end
21
+ let(:missing_mailbox_response) { OpenStruct.new(data: missing_mailbox_data) }
20
22
  let(:missing_mailbox_error) do
21
23
  Net::IMAP::NoResponseError.new(missing_mailbox_response)
22
24
  end
23
25
  let(:responses) { [] }
24
26
  let(:append_response) { nil }
25
27
 
26
- subject { described_class.new(connection, "my_folder") }
27
-
28
28
  context "#uids" do
29
29
  let(:uids) { [5678, 123] }
30
30
 
@@ -46,7 +46,7 @@ describe Imap::Backup::Account::Folder do
46
46
  end
47
47
 
48
48
  context "#fetch" do
49
- let(:message_body) { double("the body", force_encoding: nil) }
49
+ let(:message_body) { instance_double(String, force_encoding: nil) }
50
50
  let(:attributes) { {"RFC822" => message_body, "other" => "xxx"} }
51
51
  let(:fetch_data_item) do
52
52
  instance_double(Net::IMAP::FetchData, attr: attributes)
@@ -134,6 +134,18 @@ describe Imap::Backup::Account::Folder do
134
134
  it "is returned" do
135
135
  expect(subject.uid_validity).to eq("uid validity")
136
136
  end
137
+
138
+ context "when the folder doesn't exist" do
139
+ before do
140
+ allow(imap).to receive(:examine).and_raise(missing_mailbox_error)
141
+ end
142
+
143
+ it "raises an error" do
144
+ expect do
145
+ subject.uid_validity
146
+ end.to raise_error(Imap::Backup::FolderNotFound)
147
+ end
148
+ end
137
149
  end
138
150
 
139
151
  context "#append" do
@@ -144,12 +156,12 @@ describe Imap::Backup::Account::Folder do
144
156
  date: Time.now
145
157
  )
146
158
  end
147
- let(:append_response) { "response" }
159
+ let(:append_response) do
160
+ OpenStruct.new(data: OpenStruct.new(code: OpenStruct.new(data: "1 2")))
161
+ end
148
162
  let(:result) { subject.append(message) }
149
163
 
150
164
  before do
151
- allow(append_response).
152
- to receive_message_chain("data.code.data") { "1 2" }
153
165
  result
154
166
  end
155
167
 
@@ -166,3 +178,5 @@ describe Imap::Backup::Account::Folder do
166
178
  end
167
179
  end
168
180
  end
181
+
182
+ # rubocop:enable RSpec/PredicateMatcher
@@ -1,4 +1,4 @@
1
- require "spec_helper"
1
+ # rubocop:disable RSpec/NestedGroups
2
2
 
3
3
  describe Imap::Backup::Configuration::Account do
4
4
  class MockHighlineMenu
@@ -19,12 +19,12 @@ describe Imap::Backup::Configuration::Account do
19
19
  end
20
20
 
21
21
  context "#initialize" do
22
+ subject { described_class.new(store, account, highline) }
23
+
22
24
  let(:store) { "store" }
23
25
  let(:account) { "account" }
24
26
  let(:highline) { "highline" }
25
27
 
26
- subject { described_class.new(store, account, highline) }
27
-
28
28
  [:store, :account, :highline].each do |param|
29
29
  it "expects #{param}" do
30
30
  expect(subject.send(param)).to eq(send(param))
@@ -33,10 +33,12 @@ describe Imap::Backup::Configuration::Account do
33
33
  end
34
34
 
35
35
  context "#run" do
36
- let(:highline) { double("Highline") }
36
+ subject { described_class.new(store, account, highline) }
37
+
38
+ let(:highline) { instance_double(HighLine) }
37
39
  let(:menu) { MockHighlineMenu.new }
38
40
  let(:store) do
39
- double("Imap::Backup::Configuration::Store", accounts: accounts)
41
+ instance_double(Imap::Backup::Configuration::Store, accounts: accounts)
40
42
  end
41
43
  let(:accounts) { [account, account1] }
42
44
  let(:account) do
@@ -45,13 +47,13 @@ describe Imap::Backup::Configuration::Account do
45
47
  server: existing_server,
46
48
  local_path: "/backup/path",
47
49
  folders: [{name: "my_folder"}],
48
- password: existing_password,
50
+ password: existing_password
49
51
  }
50
52
  end
51
53
  let(:account1) do
52
54
  {
53
55
  username: other_email,
54
- local_path: other_existing_path,
56
+ local_path: other_existing_path
55
57
  }
56
58
  end
57
59
  let(:existing_email) { "user@example.com" }
@@ -62,21 +64,19 @@ describe Imap::Backup::Configuration::Account do
62
64
  let(:other_existing_path) { "/other/existing/path" }
63
65
 
64
66
  before do
65
- allow(subject).to receive(:system).and_return(nil)
66
- allow(subject).to receive(:puts).and_return(nil)
67
+ allow(Kernel).to receive(:system)
68
+ allow(Kernel).to receive(:puts)
67
69
  allow(highline).to receive(:choose) do |&block|
68
70
  block.call(menu)
69
71
  throw :done
70
72
  end
71
73
  end
72
74
 
73
- subject { described_class.new(store, account, highline) }
74
-
75
75
  context "preparation" do
76
76
  before { subject.run }
77
77
 
78
78
  it "clears the screen" do
79
- expect(subject).to have_received(:system).with("clear")
79
+ expect(Kernel).to have_received(:system).with("clear")
80
80
  end
81
81
 
82
82
  context "menu" do
@@ -96,7 +96,7 @@ describe Imap::Backup::Configuration::Account do
96
96
  "test connection",
97
97
  "delete",
98
98
  "return to main menu",
99
- "quit", # TODO: quit is hidden
99
+ "quit" # TODO: quit is hidden
100
100
  ].each do |item|
101
101
  before { subject.run }
102
102
 
@@ -180,7 +180,7 @@ describe Imap::Backup::Configuration::Account do
180
180
  let(:new_email) { other_email }
181
181
 
182
182
  it "indicates the error" do
183
- expect(subject).to have_received(:puts).
183
+ expect(Kernel).to have_received(:puts).
184
184
  with("There is already an account set up with that email address")
185
185
  end
186
186
 
@@ -226,9 +226,6 @@ describe Imap::Backup::Configuration::Account do
226
226
 
227
227
  before do
228
228
  allow(highline).to receive(:ask).with("server: ").and_return(server)
229
- end
230
-
231
- before do
232
229
  subject.run
233
230
  menu.choices["modify server"].call
234
231
  end
@@ -247,7 +244,7 @@ describe Imap::Backup::Configuration::Account do
247
244
  @validator = nil
248
245
  allow(
249
246
  Imap::Backup::Configuration::Asker
250
- ).to receive(:backup_path) do |path, validator|
247
+ ).to receive(:backup_path) do |_path, validator|
251
248
  @validator = validator
252
249
  new_backup_path
253
250
  end
@@ -260,14 +257,18 @@ describe Imap::Backup::Configuration::Account do
260
257
  end
261
258
 
262
259
  it "validates that the path is not used by other backups" do
260
+ # rubocop:disable RSpec/InstanceVariable
263
261
  expect(@validator.call(other_existing_path)).to be_falsey
262
+ # rubocop:enable RSpec/InstanceVariable
264
263
  end
265
264
 
266
265
  include_examples "it flags the account as modified"
267
266
  end
268
267
 
269
268
  context "folders" do
270
- let(:chooser) { double(run: nil) }
269
+ let(:chooser) do
270
+ instance_double(Imap::Backup::Configuration::FolderChooser, run: nil)
271
+ end
271
272
 
272
273
  before do
273
274
  allow(Imap::Backup::Configuration::FolderChooser).
@@ -323,3 +324,5 @@ describe Imap::Backup::Configuration::Account do
323
324
  end
324
325
  end
325
326
  end
327
+
328
+ # rubocop:enable RSpec/NestedGroups
@@ -1,34 +1,34 @@
1
- require "spec_helper"
1
+ # rubocop:disable Metrics/ModuleLength
2
2
 
3
3
  module Imap::Backup
4
4
  describe Configuration::Asker do
5
+ subject { described_class.new(highline) }
6
+
5
7
  let(:highline) { double }
6
8
  let(:query) do
7
- double(
8
- "Query",
9
- :default= => nil,
10
- :readline= => nil,
11
- :validate= => nil,
12
- :responses => {},
13
- :echo= => nil
9
+ instance_double(
10
+ HighLine::Question,
11
+ "default=": nil,
12
+ "readline=": nil,
13
+ "validate=": nil,
14
+ "responses": {},
15
+ "echo=": nil
14
16
  )
15
17
  end
16
18
  let(:answer) { "foo" }
17
19
 
18
20
  before do
19
- allow(Configuration::Setup).to receive(:highline).and_return(highline)
21
+ allow(Configuration::Setup).to receive(:highline) { highline }
20
22
  allow(highline).to receive(:ask) do |&b|
21
23
  b.call query
22
24
  answer
23
25
  end
24
26
  end
25
27
 
26
- subject { described_class.new(highline) }
27
-
28
28
  [
29
29
  [:email, [], "email address"],
30
30
  [:password, [], "password"],
31
- [:backup_path, ["x", "y"], "backup directory"]
31
+ [:backup_path, %w(x y), "backup directory"]
32
32
  ].each do |method, params, prompt|
33
33
  context ".#{method}" do
34
34
  it "asks for input" do
@@ -58,39 +58,35 @@ module Imap::Backup
58
58
  context "#email" do
59
59
  let(:email) { "email@example.com" }
60
60
  let(:answer) { email }
61
+ let(:result) { subject.email }
61
62
 
62
- before do
63
- @result = subject.email
64
- end
63
+ before { result }
65
64
 
66
65
  it "asks for an email" do
67
66
  expect(highline).to have_received(:ask).with(/email/)
68
67
  end
69
68
 
70
69
  it "returns the address" do
71
- expect(@result).to eq(email)
70
+ expect(result).to eq(email)
72
71
  end
73
72
  end
74
73
 
75
74
  context "#password" do
76
75
  let(:password1) { "password" }
77
76
  let(:password2) { "password" }
78
- let(:answers) { [answer1, answer2] }
79
- let(:answer1) { true }
80
- let(:answer2) { false }
77
+ let(:answers) { [true, false] }
78
+ let(:result) { subject.password }
81
79
 
82
80
  before do
83
- @i = 0
84
- allow(highline).to receive(:ask).
85
- with("password: ").and_return(password1)
86
- allow(highline).to receive(:ask).
87
- with("repeat password: ").and_return(password2)
81
+ i = 0
82
+ allow(highline).to receive(:ask).with("password: ") { password1 }
83
+ allow(highline).to receive(:ask).with("repeat password: ") { password2 }
88
84
  allow(highline).to receive(:agree) do
89
- answer = answers[@i]
90
- @i += 1
85
+ answer = answers[i]
86
+ i += 1
91
87
  answer
92
88
  end
93
- @result = subject.password
89
+ result
94
90
  end
95
91
 
96
92
  it "asks for a password" do
@@ -102,7 +98,7 @@ module Imap::Backup
102
98
  end
103
99
 
104
100
  it "returns the password" do
105
- expect(@result).to eq(password1)
101
+ expect(result).to eq(password1)
106
102
  end
107
103
 
108
104
  context "different answers" do
@@ -110,7 +106,7 @@ module Imap::Backup
110
106
 
111
107
  it "asks to continue" do
112
108
  expect(highline).to have_received(:agree).
113
- at_least(1).times.with(/Continue\?/)
109
+ at_least(:once).with(/Continue\?/)
114
110
  end
115
111
  end
116
112
  end
@@ -118,13 +114,14 @@ module Imap::Backup
118
114
  context "#backup_path" do
119
115
  let(:path) { "/path" }
120
116
  let(:answer) { path }
117
+ let(:result) { subject.backup_path("", //) }
121
118
 
122
119
  before do
123
120
  allow(highline).to receive(:ask) do |&b|
124
121
  b.call query
125
122
  path
126
123
  end
127
- @result = subject.backup_path("", //)
124
+ result
128
125
  end
129
126
 
130
127
  it "asks for a directory" do
@@ -132,8 +129,10 @@ module Imap::Backup
132
129
  end
133
130
 
134
131
  it "returns the path" do
135
- expect(@result).to eq(path)
132
+ expect(result).to eq(path)
136
133
  end
137
134
  end
138
135
  end
139
136
  end
137
+
138
+ # rubocop:enable Metrics/ModuleLength