imap-backup 4.0.1 → 4.0.5

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -1
  3. data/docs/development.md +5 -12
  4. data/imap-backup.gemspec +1 -4
  5. data/lib/email/mboxrd/message.rb +6 -2
  6. data/lib/email/provider/apple_mail.rb +7 -0
  7. data/lib/email/provider/base.rb +8 -0
  8. data/lib/email/provider/fastmail.rb +7 -0
  9. data/lib/email/provider/gmail.rb +7 -0
  10. data/lib/email/provider/unknown.rb +11 -0
  11. data/lib/email/provider.rb +16 -26
  12. data/lib/imap/backup/account/connection.rb +19 -29
  13. data/lib/imap/backup/account/folder.rb +9 -10
  14. data/lib/imap/backup/account.rb +103 -0
  15. data/lib/imap/backup/cli/helpers.rb +14 -0
  16. data/lib/imap/backup/cli/local.rb +19 -25
  17. data/lib/imap/backup/cli/utils.rb +67 -10
  18. data/lib/imap/backup/client/apple_mail.rb +11 -0
  19. data/lib/imap/backup/client/default.rb +51 -0
  20. data/lib/imap/backup/configuration/account.rb +3 -1
  21. data/lib/imap/backup/configuration/connection_tester.rb +1 -1
  22. data/lib/imap/backup/configuration/store.rb +10 -5
  23. data/lib/imap/backup/downloader.rb +3 -4
  24. data/lib/imap/backup/serializer/mbox.rb +5 -0
  25. data/lib/imap/backup/serializer/mbox_store.rb +8 -8
  26. data/lib/imap/backup/thunderbird/mailbox_exporter.rb +58 -0
  27. data/lib/imap/backup/version.rb +1 -1
  28. data/lib/imap/backup.rb +1 -0
  29. data/lib/thunderbird/install.rb +16 -0
  30. data/lib/thunderbird/local_folder.rb +65 -0
  31. data/lib/thunderbird/profile.rb +30 -0
  32. data/lib/thunderbird/profiles.rb +71 -0
  33. data/lib/thunderbird/subdirectory.rb +96 -0
  34. data/lib/thunderbird/subdirectory_placeholder.rb +21 -0
  35. data/lib/thunderbird.rb +14 -0
  36. data/spec/features/restore_spec.rb +1 -1
  37. data/spec/features/support/email_server.rb +2 -2
  38. data/spec/unit/email/provider/apple_mail_spec.rb +7 -0
  39. data/spec/unit/email/provider/base_spec.rb +11 -0
  40. data/spec/unit/email/provider/fastmail_spec.rb +7 -0
  41. data/spec/unit/email/provider/gmail_spec.rb +7 -0
  42. data/spec/unit/email/provider_spec.rb +12 -25
  43. data/spec/unit/imap/backup/account/connection_spec.rb +26 -51
  44. data/spec/unit/imap/backup/account/folder_spec.rb +22 -22
  45. data/spec/unit/imap/backup/cli/local_spec.rb +70 -0
  46. data/spec/unit/imap/backup/cli/utils_spec.rb +50 -0
  47. data/spec/unit/imap/backup/client/default_spec.rb +22 -0
  48. data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +3 -3
  49. data/spec/unit/imap/backup/configuration/store_spec.rb +25 -12
  50. data/spec/unit/imap/backup/downloader_spec.rb +1 -2
  51. metadata +68 -30
@@ -152,7 +152,7 @@ RSpec.describe "restore", type: :feature, docker: true do
152
152
  it "maintains encodings" do
153
153
  message =
154
154
  server_messages(folder).
155
- first["RFC822"]
155
+ first["BODY[]"]
156
156
 
157
157
  expect(message).to eq(server_message)
158
158
  end
@@ -1,5 +1,5 @@
1
1
  module EmailServerHelpers
2
- REQUESTED_ATTRIBUTES = %w(RFC822 FLAGS INTERNALDATE).freeze
2
+ REQUESTED_ATTRIBUTES = ["BODY[]"].freeze
3
3
  DEFAULT_EMAIL = "address@example.org".freeze
4
4
 
5
5
  def send_email(folder, options)
@@ -28,7 +28,7 @@ module EmailServerHelpers
28
28
  end
29
29
 
30
30
  def server_message_to_body(message)
31
- message["RFC822"]
31
+ message["BODY[]"]
32
32
  end
33
33
 
34
34
  def server_fetch_email(folder, uid)
@@ -0,0 +1,7 @@
1
+ describe Email::Provider::AppleMail do
2
+ describe "#host" do
3
+ it "returns host" do
4
+ expect(subject.host).to eq("imap.mail.me.com")
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ describe Email::Provider::Default do
2
+ describe "#options" do
3
+ it "returns options" do
4
+ expect(subject.options).to be_a(Hash)
5
+ end
6
+
7
+ it "forces TLSv1_2" do
8
+ expect(subject.options[:ssl][:ssl_version]).to eq(:TLSv1_2)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ describe Email::Provider::Fastmail do
2
+ describe "#host" do
3
+ it "returns host" do
4
+ expect(subject.host).to eq("imap.fastmail.com")
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ describe Email::Provider::GMail do
2
+ describe "#host" do
3
+ it "returns host" do
4
+ expect(subject.host).to eq("imap.gmail.com")
5
+ end
6
+ end
7
+ end
@@ -1,40 +1,27 @@
1
1
  describe Email::Provider do
2
- subject { described_class.new(:gmail) }
3
-
4
2
  describe ".for_address" do
5
3
  context "with known providers" do
6
4
  [
7
- ["gmail.com", :gmail],
8
- ["fastmail.fm", :fastmail]
9
- ].each do |domain, provider|
10
- it "recognizes #{provider}" do
5
+ ["fastmail.com", "Fastmail .com", Email::Provider::Fastmail],
6
+ ["fastmail.fm", "Fastmail .fm", Email::Provider::Fastmail],
7
+ ["gmail.com", "GMail", Email::Provider::GMail],
8
+ ["icloud.com", "Apple Mail icloud.com", Email::Provider::AppleMail],
9
+ ["mac.com", "Apple Mail mac.com", Email::Provider::AppleMail],
10
+ ["me.com", "Apple Mail me.com", Email::Provider::AppleMail]
11
+ ].each do |domain, name, klass|
12
+ it "recognizes #{name} addresses" do
11
13
  address = "foo@#{domain}"
12
- expect(described_class.for_address(address).provider).to eq(provider)
14
+ expect(described_class.for_address(address)).to be_a(klass)
13
15
  end
14
16
  end
15
17
  end
16
18
 
17
19
  context "with unknown providers" do
18
20
  it "returns a default provider" do
19
- result = described_class.for_address("foo@unknown.com").provider
20
- expect(result).to eq(:default)
21
- end
22
- end
23
- end
24
-
25
- describe "#options" do
26
- it "returns options" do
27
- expect(subject.options).to be_a(Hash)
28
- end
21
+ result = described_class.for_address("foo@unknown.com")
29
22
 
30
- it "forces TLSv1_2" do
31
- expect(subject.options[:ssl][:ssl_version]).to eq(:TLSv1_2)
32
- end
33
- end
34
-
35
- describe "#host" do
36
- it "returns host" do
37
- expect(subject.host).to eq("imap.gmail.com")
23
+ expect(result).to be_a(Email::Provider::Default)
24
+ end
38
25
  end
39
26
  end
40
27
  end
@@ -14,8 +14,10 @@ describe Imap::Backup::Account::Connection do
14
14
 
15
15
  subject { described_class.new(options) }
16
16
 
17
- let(:imap) do
18
- instance_double(Net::IMAP, authenticate: nil, login: nil, disconnect: nil)
17
+ let(:client) do
18
+ instance_double(
19
+ Imap::Backup::Client::Default, authenticate: nil, login: nil, disconnect: nil
20
+ )
19
21
  end
20
22
  let(:imap_folders) { [] }
21
23
  let(:options) do
@@ -45,15 +47,14 @@ describe Imap::Backup::Account::Connection do
45
47
  let(:new_uid_validity) { nil }
46
48
 
47
49
  before do
48
- allow(Net::IMAP).to receive(:new) { imap }
49
- allow(imap).to receive(:list).with("", "") { [root_info] }
50
- allow(imap).to receive(:list).with(ROOT_NAME, "*") { imap_folders }
50
+ allow(Imap::Backup::Client::Default).to receive(:new) { client }
51
+ allow(client).to receive(:list) { imap_folders }
51
52
  allow(Imap::Backup::Utils).to receive(:make_folder)
52
53
  end
53
54
 
54
55
  shared_examples "connects to IMAP" do
55
56
  it "logs in to the imap server" do
56
- expect(imap).to have_received(:login)
57
+ expect(client).to have_received(:login)
57
58
  end
58
59
  end
59
60
 
@@ -76,48 +77,34 @@ describe Imap::Backup::Account::Connection do
76
77
  end
77
78
  end
78
79
 
79
- describe "#imap" do
80
- let(:result) { subject.imap }
80
+ describe "#client" do
81
+ let(:result) { subject.client }
81
82
 
82
83
  it "returns the IMAP connection" do
83
- expect(result).to eq(imap)
84
+ expect(result).to eq(client)
84
85
  end
85
86
 
86
87
  it "uses the password" do
87
88
  result
88
89
 
89
- expect(imap).to have_received(:login).with(USERNAME, PASSWORD)
90
- end
91
-
92
- context "with the GMail IMAP server" do
93
- let(:server) { GMAIL_IMAP_SERVER }
94
- let(:refresh_token) { true }
95
- let(:result) { nil }
96
-
97
- context "when the password is not our copy of a GMail refresh token" do
98
- it "uses the password" do
99
- subject.imap
100
-
101
- expect(imap).to have_received(:login).with(USERNAME, PASSWORD)
102
- end
103
- end
90
+ expect(client).to have_received(:login).with(USERNAME, PASSWORD)
104
91
  end
105
92
 
106
93
  context "when the first login attempt fails" do
107
94
  before do
108
95
  outcomes = [-> { raise EOFError }, -> { true }]
109
- allow(imap).to receive(:login) { outcomes.shift.call }
96
+ allow(client).to receive(:login) { outcomes.shift.call }
110
97
  end
111
98
 
112
99
  it "retries" do
113
- subject.imap
100
+ subject.client
114
101
 
115
- expect(imap).to have_received(:login).twice
102
+ expect(client).to have_received(:login).twice
116
103
  end
117
104
  end
118
105
 
119
106
  context "when run" do
120
- before { subject.imap }
107
+ before { subject.client }
121
108
 
122
109
  include_examples "connects to IMAP"
123
110
  end
@@ -125,22 +112,12 @@ describe Imap::Backup::Account::Connection do
125
112
 
126
113
  describe "#folders" do
127
114
  let(:imap_folders) do
128
- [instance_double(Net::IMAP::MailboxList, name: BACKUP_FOLDER)]
115
+ [BACKUP_FOLDER]
129
116
  end
130
117
 
131
118
  it "returns the list of folders" do
132
119
  expect(subject.folders).to eq([BACKUP_FOLDER])
133
120
  end
134
-
135
- context "with non-ASCII folder names" do
136
- let(:imap_folders) do
137
- [instance_double(Net::IMAP::MailboxList, name: "Gel&APY-scht")]
138
- end
139
-
140
- it "converts them to UTF-8" do
141
- expect(subject.folders).to eq(["Gelöscht"])
142
- end
143
- end
144
121
  end
145
122
 
146
123
  describe "#status" do
@@ -208,9 +185,7 @@ describe Imap::Backup::Account::Connection do
208
185
  end
209
186
 
210
187
  context "without supplied config_folders" do
211
- let(:imap_folders) do
212
- [instance_double(Net::IMAP::MailboxList, name: ROOT_NAME)]
213
- end
188
+ let(:imap_folders) { [ROOT_NAME] }
214
189
 
215
190
  before do
216
191
  allow(Imap::Backup::Account::Folder).to receive(:new).
@@ -241,7 +216,7 @@ describe Imap::Backup::Account::Connection do
241
216
 
242
217
  context "when the imap server doesn't return folders" do
243
218
  let(:config_folders) { nil }
244
- let(:imap_folders) { nil }
219
+ let(:imap_folders) { [] }
245
220
 
246
221
  it "fails" do
247
222
  expect do
@@ -389,10 +364,10 @@ describe Imap::Backup::Account::Connection do
389
364
 
390
365
  describe "#reconnect" do
391
366
  context "when the IMAP connection has been used" do
392
- before { subject.imap }
367
+ before { subject.client }
393
368
 
394
369
  it "disconnects from the server" do
395
- expect(imap).to receive(:disconnect)
370
+ expect(client).to receive(:disconnect)
396
371
 
397
372
  subject.reconnect
398
373
  end
@@ -400,26 +375,26 @@ describe Imap::Backup::Account::Connection do
400
375
 
401
376
  context "when the IMAP connection has not been used" do
402
377
  it "does not disconnect from the server" do
403
- expect(imap).to_not receive(:disconnect)
378
+ expect(client).to_not receive(:disconnect)
404
379
 
405
380
  subject.reconnect
406
381
  end
407
382
  end
408
383
 
409
384
  it "causes reconnection on future access" do
410
- expect(Net::IMAP).to receive(:new)
385
+ expect(Imap::Backup::Client::Default).to receive(:new)
411
386
 
412
387
  subject.reconnect
413
- subject.imap
388
+ subject.client
414
389
  end
415
390
  end
416
391
 
417
392
  describe "#disconnect" do
418
393
  context "when the IMAP connection has been used" do
419
394
  it "disconnects from the server" do
420
- subject.imap
395
+ subject.client
421
396
 
422
- expect(imap).to receive(:disconnect)
397
+ expect(client).to receive(:disconnect)
423
398
 
424
399
  subject.disconnect
425
400
  end
@@ -427,7 +402,7 @@ describe Imap::Backup::Account::Connection do
427
402
 
428
403
  context "when the IMAP connection has not been used" do
429
404
  it "does not disconnect from the server" do
430
- expect(imap).to_not receive(:disconnect)
405
+ expect(client).to_not receive(:disconnect)
431
406
 
432
407
  subject.disconnect
433
408
  end
@@ -6,9 +6,9 @@ describe Imap::Backup::Account::Folder do
6
6
 
7
7
  subject { described_class.new(connection, FOLDER_NAME) }
8
8
 
9
- let(:imap) do
9
+ let(:client) do
10
10
  instance_double(
11
- Net::IMAP,
11
+ Imap::Backup::Client::Default,
12
12
  append: append_response,
13
13
  create: nil,
14
14
  examine: nil,
@@ -16,7 +16,7 @@ describe Imap::Backup::Account::Folder do
16
16
  )
17
17
  end
18
18
  let(:connection) do
19
- instance_double(Imap::Backup::Account::Connection, imap: imap)
19
+ instance_double(Imap::Backup::Account::Connection, client: client)
20
20
  end
21
21
  let(:missing_mailbox_data) do
22
22
  OpenStruct.new(text: "Unknown Mailbox: #{FOLDER_NAME}")
@@ -31,7 +31,7 @@ describe Imap::Backup::Account::Folder do
31
31
  describe "#uids" do
32
32
  let(:uids) { [5678, 123] }
33
33
 
34
- before { allow(imap).to receive(:uid_search) { uids } }
34
+ before { allow(client).to receive(:uid_search) { uids } }
35
35
 
36
36
  it "lists available messages" do
37
37
  expect(subject.uids).to eq(uids.reverse)
@@ -39,7 +39,7 @@ describe Imap::Backup::Account::Folder do
39
39
 
40
40
  context "with missing mailboxes" do
41
41
  before do
42
- allow(imap).to receive(:examine).
42
+ allow(client).to receive(:examine).
43
43
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
44
44
  end
45
45
 
@@ -54,7 +54,7 @@ describe Imap::Backup::Account::Folder do
54
54
  end
55
55
 
56
56
  before do
57
- allow(imap).to receive(:examine).
57
+ allow(client).to receive(:examine).
58
58
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
59
59
  end
60
60
 
@@ -66,19 +66,19 @@ describe Imap::Backup::Account::Folder do
66
66
 
67
67
  describe "#fetch" do
68
68
  let(:message_body) { instance_double(String, force_encoding: nil) }
69
- let(:attributes) { {"RFC822" => message_body, "other" => "xxx"} }
69
+ let(:attributes) { {"BODY[]" => message_body, "other" => "xxx"} }
70
70
  let(:fetch_data_item) do
71
71
  instance_double(Net::IMAP::FetchData, attr: attributes)
72
72
  end
73
73
 
74
- before { allow(imap).to receive(:uid_fetch) { [fetch_data_item] } }
74
+ before { allow(client).to receive(:uid_fetch) { [fetch_data_item] } }
75
75
 
76
76
  it "returns the message" do
77
- expect(subject.fetch(123)).to eq(attributes)
77
+ expect(subject.fetch(123)).to eq(message_body)
78
78
  end
79
79
 
80
80
  context "when the server responds with nothing" do
81
- before { allow(imap).to receive(:uid_fetch) { nil } }
81
+ before { allow(client).to receive(:uid_fetch) { nil } }
82
82
 
83
83
  it "is nil" do
84
84
  expect(subject.fetch(123)).to be_nil
@@ -87,7 +87,7 @@ describe Imap::Backup::Account::Folder do
87
87
 
88
88
  context "when the mailbox doesn't exist" do
89
89
  before do
90
- allow(imap).to receive(:examine).
90
+ allow(client).to receive(:examine).
91
91
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
92
92
  end
93
93
 
@@ -96,7 +96,7 @@ describe Imap::Backup::Account::Folder do
96
96
  end
97
97
  end
98
98
 
99
- context "when the response doesn't have RFC822" do
99
+ context "when the response doesn't include 'BODY[]'" do
100
100
  let(:attributes) { {} }
101
101
 
102
102
  it "is nil" do
@@ -107,13 +107,13 @@ describe Imap::Backup::Account::Folder do
107
107
  context "when the first fetch_uid attempts fail" do
108
108
  before do
109
109
  outcomes = [-> { raise EOFError }, -> { [fetch_data_item] }]
110
- allow(imap).to receive(:uid_fetch) { outcomes.shift.call }
110
+ allow(client).to receive(:uid_fetch) { outcomes.shift.call }
111
111
  end
112
112
 
113
113
  it "retries" do
114
114
  subject.fetch(123)
115
115
 
116
- expect(imap).to have_received(:uid_fetch).twice
116
+ expect(client).to have_received(:uid_fetch).twice
117
117
  end
118
118
 
119
119
  it "succeeds" do
@@ -137,7 +137,7 @@ describe Imap::Backup::Account::Folder do
137
137
 
138
138
  context "when the folder doesn't exist" do
139
139
  before do
140
- allow(imap).to receive(:examine).
140
+ allow(client).to receive(:examine).
141
141
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
142
142
  end
143
143
 
@@ -150,7 +150,7 @@ describe Imap::Backup::Account::Folder do
150
150
  describe "#create" do
151
151
  context "when the folder exists" do
152
152
  it "is does not create the folder" do
153
- expect(imap).to_not receive(:create)
153
+ expect(client).to_not receive(:create)
154
154
 
155
155
  subject.create
156
156
  end
@@ -158,18 +158,18 @@ describe Imap::Backup::Account::Folder do
158
158
 
159
159
  context "when the folder doesn't exist" do
160
160
  before do
161
- allow(imap).to receive(:examine).
161
+ allow(client).to receive(:examine).
162
162
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
163
163
  end
164
164
 
165
165
  it "creates the folder" do
166
- expect(imap).to receive(:create)
166
+ expect(client).to receive(:create)
167
167
 
168
168
  subject.create
169
169
  end
170
170
 
171
171
  it "encodes the folder name" do
172
- expect(imap).to receive(:create).with(ENCODED_FOLDER_NAME)
172
+ expect(client).to receive(:create).with(ENCODED_FOLDER_NAME)
173
173
 
174
174
  subject.create
175
175
  end
@@ -185,7 +185,7 @@ describe Imap::Backup::Account::Folder do
185
185
 
186
186
  context "when the folder doesn't exist" do
187
187
  before do
188
- allow(imap).to receive(:examine).
188
+ allow(client).to receive(:examine).
189
189
  with(ENCODED_FOLDER_NAME).and_raise(missing_mailbox_error)
190
190
  end
191
191
 
@@ -211,13 +211,13 @@ describe Imap::Backup::Account::Folder do
211
211
  end
212
212
 
213
213
  it "appends the message" do
214
- expect(imap).to receive(:append)
214
+ expect(client).to receive(:append)
215
215
 
216
216
  subject.append(message)
217
217
  end
218
218
 
219
219
  it "sets the date and time" do
220
- expect(imap).to receive(:append).
220
+ expect(client).to receive(:append).
221
221
  with(anything, anything, anything, message_date)
222
222
 
223
223
  subject.append(message)
@@ -0,0 +1,70 @@
1
+ describe Imap::Backup::CLI::Local do
2
+ let(:list) do
3
+ instance_double(Imap::Backup::Configuration::List, accounts: accounts)
4
+ end
5
+ let(:accounts) { [{username: email}] }
6
+ let(:connection) do
7
+ instance_double(
8
+ Imap::Backup::Account::Connection,
9
+ local_folders: local_folders
10
+ )
11
+ end
12
+ let(:local_folders) { [[serializer, folder]] }
13
+ let(:folder) { instance_double(Imap::Backup::Account::Folder, name: "bar") }
14
+ let(:serializer) do
15
+ instance_double(
16
+ Imap::Backup::Serializer::Mbox,
17
+ uids: uids,
18
+ each_message: [[123, message]]
19
+ )
20
+ end
21
+ let(:uids) { ["123"] }
22
+ let(:message) do
23
+ instance_double(
24
+ Email::Mboxrd::Message,
25
+ date: Date.today,
26
+ subject: "Ciao",
27
+ supplied_body: "Supplied"
28
+ )
29
+ end
30
+ let(:email) { "foo@example.com" }
31
+
32
+ before do
33
+ allow(Kernel).to receive(:puts)
34
+ allow(Imap::Backup::Configuration::List).to receive(:new) { list }
35
+ allow(Imap::Backup::Account::Connection).to receive(:new) { connection }
36
+ allow(Mail).to receive(:new) { mail }
37
+ end
38
+
39
+ describe "accounts" do
40
+ it "lists configured emails" do
41
+ subject.accounts
42
+
43
+ expect(Kernel).to have_received(:puts).with(email)
44
+ end
45
+ end
46
+
47
+ describe "folders" do
48
+ it "lists downloaded folders in quotes" do
49
+ subject.folders(email)
50
+
51
+ expect(Kernel).to have_received(:puts).with(%("bar"))
52
+ end
53
+ end
54
+
55
+ describe "list" do
56
+ it "lists downloaded emails" do
57
+ subject.list(email, "bar")
58
+
59
+ expect(Kernel).to have_received(:puts).with(/Ciao/)
60
+ end
61
+ end
62
+
63
+ describe "show" do
64
+ it "prints a downloaded email" do
65
+ subject.show(email, "bar", "123")
66
+
67
+ expect(Kernel).to have_received(:puts).with("Supplied")
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,50 @@
1
+ describe Imap::Backup::CLI::Utils do
2
+ let(:list) do
3
+ instance_double(Imap::Backup::Configuration::List, accounts: accounts)
4
+ end
5
+ let(:accounts) { [{username: email}] }
6
+ let(:connection) do
7
+ instance_double(
8
+ Imap::Backup::Account::Connection,
9
+ local_folders: local_folders
10
+ )
11
+ end
12
+ let(:local_folders) { [[serializer, folder]] }
13
+ let(:folder) do
14
+ instance_double(
15
+ Imap::Backup::Account::Folder,
16
+ exist?: true,
17
+ name: "name",
18
+ uid_validity: "uid_validity",
19
+ uids: %w(123 456)
20
+ )
21
+ end
22
+ let(:serializer) do
23
+ instance_double(
24
+ Imap::Backup::Serializer::Mbox,
25
+ uids: %w(123 789),
26
+ apply_uid_validity: nil,
27
+ save: nil
28
+ )
29
+ end
30
+ let(:email) { "foo@example.com" }
31
+
32
+ before do
33
+ allow(Imap::Backup::Configuration::List).to receive(:new) { list }
34
+ allow(Imap::Backup::Account::Connection).to receive(:new) { connection }
35
+ end
36
+
37
+ describe "ignore_history" do
38
+ it "ensures the local UID validity matches the server" do
39
+ subject.ignore_history(email)
40
+
41
+ expect(serializer).to have_received(:apply_uid_validity).with("uid_validity")
42
+ end
43
+
44
+ it "fills the local folder with fake emails" do
45
+ subject.ignore_history(email)
46
+
47
+ expect(serializer).to have_received(:save).with("456", /From: fake@email.com/)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,22 @@
1
+ describe Imap::Backup::Client::Default do
2
+ subject { described_class.new("server", {}) }
3
+
4
+ let(:imap) { instance_double(Net::IMAP, list: imap_folders) }
5
+ let(:imap_folders) { [] }
6
+
7
+ before do
8
+ allow(Net::IMAP).to receive(:new) { imap }
9
+ end
10
+
11
+ describe "#list" do
12
+ context "with non-ASCII folder names" do
13
+ let(:imap_folders) do
14
+ [instance_double(Net::IMAP::MailboxList, name: "Gel&APY-scht")]
15
+ end
16
+
17
+ it "converts them to UTF-8" do
18
+ expect(subject.list).to eq(["Gelöscht"])
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,7 +1,7 @@
1
1
  describe Imap::Backup::Configuration::ConnectionTester do
2
2
  describe ".test" do
3
3
  let(:connection) do
4
- instance_double(Imap::Backup::Account::Connection, imap: nil)
4
+ instance_double(Imap::Backup::Account::Connection, client: nil)
5
5
  end
6
6
 
7
7
  before do
@@ -10,7 +10,7 @@ describe Imap::Backup::Configuration::ConnectionTester do
10
10
 
11
11
  describe "call" do
12
12
  it "tries to connect" do
13
- expect(connection).to receive(:imap)
13
+ expect(connection).to receive(:client)
14
14
 
15
15
  subject.test("foo")
16
16
  end
@@ -24,7 +24,7 @@ describe Imap::Backup::Configuration::ConnectionTester do
24
24
 
25
25
  describe "failure" do
26
26
  before do
27
- allow(connection).to receive(:imap).and_raise(error)
27
+ allow(connection).to receive(:client).and_raise(error)
28
28
  end
29
29
 
30
30
  context "with no connection" do