imap-backup 4.0.3 → 4.0.7

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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/email/provider/apple_mail.rb +2 -2
  3. data/lib/email/provider/base.rb +8 -0
  4. data/lib/email/provider/fastmail.rb +2 -2
  5. data/lib/email/provider/gmail.rb +2 -2
  6. data/lib/email/provider/{default.rb → unknown.rb} +2 -3
  7. data/lib/email/provider.rb +2 -2
  8. data/lib/imap/backup/account/connection.rb +23 -31
  9. data/lib/imap/backup/account/folder.rb +1 -1
  10. data/lib/imap/backup/account.rb +98 -0
  11. data/lib/imap/backup/cli/helpers.rb +1 -1
  12. data/lib/imap/backup/cli/local.rb +1 -1
  13. data/lib/imap/backup/configuration/account.rb +38 -30
  14. data/lib/imap/backup/configuration/folder_chooser.rb +7 -9
  15. data/lib/imap/backup/configuration/list.rb +1 -1
  16. data/lib/imap/backup/configuration/setup.rb +10 -8
  17. data/lib/imap/backup/configuration/store.rb +33 -11
  18. data/lib/imap/backup/version.rb +1 -1
  19. data/lib/imap/backup.rb +1 -0
  20. data/spec/features/support/shared/connection_context.rb +7 -5
  21. data/spec/unit/email/provider/{default_spec.rb → base_spec.rb} +1 -7
  22. data/spec/unit/email/provider_spec.rb +2 -2
  23. data/spec/unit/imap/backup/account/connection_spec.rb +8 -17
  24. data/spec/unit/imap/backup/cli/local_spec.rb +9 -2
  25. data/spec/unit/imap/backup/cli/utils_spec.rb +44 -42
  26. data/spec/unit/imap/backup/configuration/account_spec.rb +47 -46
  27. data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +17 -18
  28. data/spec/unit/imap/backup/configuration/list_spec.rb +12 -5
  29. data/spec/unit/imap/backup/configuration/setup_spec.rb +33 -12
  30. data/spec/unit/imap/backup/configuration/store_spec.rb +21 -22
  31. metadata +32 -32
  32. data/spec/support/shared_examples/account_flagging.rb +0 -23
@@ -1,11 +1,14 @@
1
1
  require "json"
2
2
  require "os"
3
3
 
4
+ require "imap/backup/account"
5
+
4
6
  module Imap::Backup
5
7
  module Configuration; end
6
8
 
7
9
  class Configuration::Store
8
10
  CONFIGURATION_DIRECTORY = File.expand_path("~/.imap-backup")
11
+ VERSION = "2.0"
9
12
 
10
13
  attr_reader :pathname
11
14
 
@@ -19,6 +22,7 @@ module Imap::Backup
19
22
 
20
23
  def initialize(pathname = self.class.default_pathname)
21
24
  @pathname = pathname
25
+ @debug = nil
22
26
  end
23
27
 
24
28
  def path
@@ -26,53 +30,71 @@ module Imap::Backup
26
30
  end
27
31
 
28
32
  def save
33
+ ensure_loaded!
29
34
  FileUtils.mkdir(path) if !File.directory?(path)
30
35
  make_private(path) if !windows?
31
36
  remove_modified_flags
32
37
  remove_deleted_accounts
33
- File.open(pathname, "w") { |f| f.write(JSON.pretty_generate(data)) }
38
+ save_data = {
39
+ version: VERSION,
40
+ accounts: accounts.map(&:to_h),
41
+ debug: debug?
42
+ }
43
+ File.open(pathname, "w") { |f| f.write(JSON.pretty_generate(save_data)) }
34
44
  FileUtils.chmod(0o600, pathname) if !windows?
35
45
  end
36
46
 
37
47
  def accounts
38
- data[:accounts]
48
+ @accounts ||= begin
49
+ ensure_loaded!
50
+ data[:accounts].map { |data| Account.new(data) }
51
+ end
39
52
  end
40
53
 
41
54
  def modified?
42
- accounts.any? { |a| a[:modified] || a[:delete] }
55
+ ensure_loaded!
56
+ accounts.any? { |a| a.modified? || a.marked_for_deletion? }
43
57
  end
44
58
 
45
59
  def debug?
46
- data[:debug]
60
+ ensure_loaded!
61
+ @debug
47
62
  end
48
63
 
49
64
  def debug=(value)
50
- data[:debug] = [true, false].include?(value) ? value : false
65
+ ensure_loaded!
66
+ @debug = [true, false].include?(value) ? value : false
51
67
  end
52
68
 
53
69
  private
54
70
 
71
+ def ensure_loaded!
72
+ return true if @data
73
+
74
+ data
75
+ @debug = data.key?(:debug) ? data[:debug] == true : false
76
+ true
77
+ end
78
+
55
79
  def data
56
80
  @data ||=
57
81
  begin
58
82
  if File.exist?(pathname)
59
83
  Utils.check_permissions(pathname, 0o600) if !windows?
60
84
  contents = File.read(pathname)
61
- data = JSON.parse(contents, symbolize_names: true)
85
+ JSON.parse(contents, symbolize_names: true)
62
86
  else
63
- data = {accounts: []}
87
+ {accounts: []}
64
88
  end
65
- data[:debug] = data.key?(:debug) ? data[:debug] == true : false
66
- data
67
89
  end
68
90
  end
69
91
 
70
92
  def remove_modified_flags
71
- accounts.each { |a| a.delete(:modified) }
93
+ accounts.each { |a| a.clear_changes! }
72
94
  end
73
95
 
74
96
  def remove_deleted_accounts
75
- accounts.reject! { |a| a[:delete] }
97
+ accounts.reject! { |a| a.marked_for_deletion? }
76
98
  end
77
99
 
78
100
  def make_private(path)
@@ -3,7 +3,7 @@ module Imap; end
3
3
  module Imap::Backup
4
4
  MAJOR = 4
5
5
  MINOR = 0
6
- REVISION = 3
6
+ REVISION = 7
7
7
  PRE = nil
8
8
  VERSION = [MAJOR, MINOR, REVISION, PRE].compact.map(&:to_s).join(".")
9
9
  end
data/lib/imap/backup.rb CHANGED
@@ -29,6 +29,7 @@ module Imap::Backup
29
29
 
30
30
  def initialize
31
31
  @logger = ::Logger.new($stdout)
32
+ $stdout.sync = true
32
33
  end
33
34
  end
34
35
 
@@ -2,11 +2,13 @@ shared_context "imap-backup connection" do
2
2
  let(:local_backup_path) { Dir.mktmpdir(nil, "tmp") }
3
3
  let(:default_connection) { fixture("connection") }
4
4
  let(:backup_folders) { nil }
5
- let(:connection_options) do
6
- default_connection.merge(
7
- local_path: local_backup_path,
8
- folders: backup_folders
5
+ let(:account) do
6
+ Imap::Backup::Account.new(
7
+ default_connection.merge(
8
+ local_path: local_backup_path,
9
+ folders: backup_folders
10
+ )
9
11
  )
10
12
  end
11
- let(:connection) { Imap::Backup::Account::Connection.new(connection_options) }
13
+ let(:connection) { Imap::Backup::Account::Connection.new(account) }
12
14
  end
@@ -1,10 +1,4 @@
1
- describe Email::Provider::Default do
2
- describe "#host" do
3
- it "is unset" do
4
- expect(subject.host).to be_nil
5
- end
6
- end
7
-
1
+ describe Email::Provider::Base do
8
2
  describe "#options" do
9
3
  it "returns options" do
10
4
  expect(subject.options).to be_a(Hash)
@@ -17,10 +17,10 @@ describe Email::Provider do
17
17
  end
18
18
 
19
19
  context "with unknown providers" do
20
- it "returns a default provider" do
20
+ it "returns the Unknown provider" do
21
21
  result = described_class.for_address("foo@unknown.com")
22
22
 
23
- expect(result).to be_a(Email::Provider::Default)
23
+ expect(result).to be_a(Email::Provider::Unknown)
24
24
  end
25
25
  end
26
26
  end
@@ -12,7 +12,7 @@ describe Imap::Backup::Account::Connection do
12
12
  SERVER = "imap.example.com".freeze
13
13
  USERNAME = "username@example.com".freeze
14
14
 
15
- subject { described_class.new(options) }
15
+ subject { described_class.new(account) }
16
16
 
17
17
  let(:client) do
18
18
  instance_double(
@@ -20,14 +20,16 @@ describe Imap::Backup::Account::Connection do
20
20
  )
21
21
  end
22
22
  let(:imap_folders) { [] }
23
- let(:options) do
24
- {
23
+ let(:account) do
24
+ instance_double(
25
+ Imap::Backup::Account,
25
26
  username: USERNAME,
26
27
  password: PASSWORD,
27
28
  local_path: LOCAL_PATH,
28
29
  folders: config_folders,
29
- server: server
30
- }
30
+ server: server,
31
+ connection_options: nil
32
+ )
31
33
  end
32
34
  let(:config_folders) { [FOLDER_CONFIG] }
33
35
  let(:root_info) do
@@ -59,21 +61,10 @@ describe Imap::Backup::Account::Connection do
59
61
  end
60
62
 
61
63
  describe "#initialize" do
62
- [
63
- [:username, USERNAME],
64
- [:password, PASSWORD],
65
- [:local_path, LOCAL_PATH],
66
- [:server, SERVER]
67
- ].each do |attr, expected|
68
- it "expects #{attr}" do
69
- expect(subject.public_send(attr)).to eq(expected)
70
- end
71
- end
72
-
73
64
  it "creates the path" do
74
65
  expect(Imap::Backup::Utils).to receive(:make_folder)
75
66
 
76
- subject.username
67
+ subject
77
68
  end
78
69
  end
79
70
 
@@ -1,8 +1,15 @@
1
1
  describe Imap::Backup::CLI::Local do
2
2
  let(:list) do
3
- instance_double(Imap::Backup::Configuration::List, accounts: accounts)
3
+ instance_double(Imap::Backup::Configuration::List, accounts: [account])
4
+ end
5
+ let(:account) do
6
+ instance_double(
7
+ Imap::Backup::Account,
8
+ username: email,
9
+ marked_for_deletion?: false,
10
+ modified?: false
11
+ )
4
12
  end
5
- let(:accounts) { [{username: email}] }
6
13
  let(:connection) do
7
14
  instance_double(
8
15
  Imap::Backup::Account::Connection,
@@ -1,50 +1,52 @@
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" }
1
+ module Imap::Backup
2
+ describe CLI::Utils do
3
+ let(:list) do
4
+ instance_double(Configuration::List, accounts: [account])
5
+ end
6
+ let(:account) { instance_double(Account, username: email) }
7
+ let(:connection) do
8
+ instance_double(
9
+ Account::Connection,
10
+ local_folders: local_folders
11
+ )
12
+ end
13
+ let(:local_folders) { [[serializer, folder]] }
14
+ let(:folder) do
15
+ instance_double(
16
+ Account::Folder,
17
+ exist?: true,
18
+ name: "name",
19
+ uid_validity: "uid_validity",
20
+ uids: %w(123 456)
21
+ )
22
+ end
23
+ let(:serializer) do
24
+ instance_double(
25
+ Serializer::Mbox,
26
+ uids: %w(123 789),
27
+ apply_uid_validity: nil,
28
+ save: nil
29
+ )
30
+ end
31
+ let(:email) { "foo@example.com" }
31
32
 
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
33
+ before do
34
+ allow(Configuration::List).to receive(:new) { list }
35
+ allow(Account::Connection).to receive(:new) { connection }
36
+ end
36
37
 
37
- describe "ignore_history" do
38
- it "ensures the local UID validity matches the server" do
39
- subject.ignore_history(email)
38
+ describe "ignore_history" do
39
+ it "ensures the local UID validity matches the server" do
40
+ subject.ignore_history(email)
40
41
 
41
- expect(serializer).to have_received(:apply_uid_validity).with("uid_validity")
42
- end
42
+ expect(serializer).to have_received(:apply_uid_validity).with("uid_validity")
43
+ end
43
44
 
44
- it "fills the local folder with fake emails" do
45
- subject.ignore_history(email)
45
+ it "fills the local folder with fake emails" do
46
+ subject.ignore_history(email)
46
47
 
47
- expect(serializer).to have_received(:save).with("456", /From: fake@email.com/)
48
+ expect(serializer).to have_received(:save).with("456", /From: fake@email.com/)
49
+ end
48
50
  end
49
51
  end
50
52
  end
@@ -6,7 +6,32 @@ describe Imap::Backup::Configuration::Account do
6
6
 
7
7
  subject { described_class.new(store, account, highline) }
8
8
 
9
- let(:account) { ACCOUNT }
9
+ let(:account) do
10
+ instance_double(
11
+ Imap::Backup::Account,
12
+ username: existing_email,
13
+ password: existing_password,
14
+ server: current_server,
15
+ connection_options: nil,
16
+ local_path: "/backup/path",
17
+ folders: [{name: "my_folder"}]
18
+ )
19
+ end
20
+ let(:account1) do
21
+ instance_double(
22
+ Imap::Backup::Account,
23
+ username: other_email,
24
+ local_path: other_existing_path
25
+ )
26
+ end
27
+ let(:accounts) { [account, account1] }
28
+ let(:existing_email) { "user@example.com" }
29
+ let(:new_email) { "foo@example.com" }
30
+ let(:current_server) { "imap.example.com" }
31
+ let(:existing_password) { "password" }
32
+ let(:other_email) { "other@example.com" }
33
+ let(:other_existing_path) { "/other/existing/path" }
34
+
10
35
  let(:highline) { HIGHLINE }
11
36
  let(:store) { STORE }
12
37
 
@@ -43,28 +68,6 @@ describe Imap::Backup::Configuration::Account do
43
68
  let(:store) do
44
69
  instance_double(Imap::Backup::Configuration::Store, accounts: accounts)
45
70
  end
46
- let(:accounts) { [account, account1] }
47
- let(:account) do
48
- {
49
- username: existing_email,
50
- server: current_server,
51
- local_path: "/backup/path",
52
- folders: [{name: "my_folder"}],
53
- password: existing_password
54
- }
55
- end
56
- let(:account1) do
57
- {
58
- username: other_email,
59
- local_path: other_existing_path
60
- }
61
- end
62
- let(:existing_email) { "user@example.com" }
63
- let(:new_email) { "foo@example.com" }
64
- let(:current_server) { "imap.example.com" }
65
- let(:existing_password) { "password" }
66
- let(:other_email) { "other@example.com" }
67
- let(:other_existing_path) { "/other/existing/path" }
68
71
 
69
72
  before do
70
73
  allow(Kernel).to receive(:system)
@@ -139,6 +142,8 @@ describe Imap::Backup::Configuration::Account do
139
142
 
140
143
  describe "choosing 'modify email'" do
141
144
  before do
145
+ allow(account).to receive(:"username=")
146
+ allow(account).to receive(:"server=")
142
147
  allow(Imap::Backup::Configuration::Asker).
143
148
  to receive(:email) { new_email }
144
149
  subject.run
@@ -158,7 +163,7 @@ describe Imap::Backup::Configuration::Account do
158
163
  let(:current_server) { nil }
159
164
 
160
165
  it "sets a default server" do
161
- expect(account[:server]).to eq(expected)
166
+ expect(account).to have_received(:"server=").with(expected)
162
167
  end
163
168
  end
164
169
 
@@ -166,7 +171,7 @@ describe Imap::Backup::Configuration::Account do
166
171
  let(:current_server) { "" }
167
172
 
168
173
  it "sets a default server" do
169
- expect(account[:server]).to eq(expected)
174
+ expect(account).to have_received(:"server=").with(expected)
170
175
  end
171
176
  end
172
177
  end
@@ -183,17 +188,15 @@ describe Imap::Backup::Configuration::Account do
183
188
  end
184
189
 
185
190
  it "does not set a default server" do
186
- expect(account[:server]).to be_nil
191
+ expect(account).to_not have_received(:"server=")
187
192
  end
188
193
  end
189
194
  end
190
195
 
191
196
  context "when the email is new" do
192
197
  it "modifies the email address" do
193
- expect(account[:username]).to eq(new_email)
198
+ expect(account).to have_received(:"username=").with(new_email)
194
199
  end
195
-
196
- include_examples "it flags the account as modified"
197
200
  end
198
201
 
199
202
  context "when the email already exists" do
@@ -205,10 +208,8 @@ describe Imap::Backup::Configuration::Account do
205
208
  end
206
209
 
207
210
  it "doesn't set the email" do
208
- expect(account[:username]).to eq(existing_email)
211
+ expect(account.username).to eq(existing_email)
209
212
  end
210
-
211
- include_examples "it doesn't flag the account as modified"
212
213
  end
213
214
  end
214
215
 
@@ -216,6 +217,7 @@ describe Imap::Backup::Configuration::Account do
216
217
  let(:new_password) { "new_password" }
217
218
 
218
219
  before do
220
+ allow(account).to receive(:"password=")
219
221
  allow(Imap::Backup::Configuration::Asker).
220
222
  to receive(:password) { new_password }
221
223
  subject.run
@@ -224,20 +226,16 @@ describe Imap::Backup::Configuration::Account do
224
226
 
225
227
  context "when the user enters a password" do
226
228
  it "updates the password" do
227
- expect(account[:password]).to eq(new_password)
229
+ expect(account).to have_received(:"password=").with(new_password)
228
230
  end
229
-
230
- include_examples "it flags the account as modified"
231
231
  end
232
232
 
233
233
  context "when the user cancels" do
234
234
  let(:new_password) { nil }
235
235
 
236
236
  it "does nothing" do
237
- expect(account[:password]).to eq(existing_password)
237
+ expect(account.password).to eq(existing_password)
238
238
  end
239
-
240
- include_examples "it doesn't flag the account as modified"
241
239
  end
242
240
  end
243
241
 
@@ -245,6 +243,7 @@ describe Imap::Backup::Configuration::Account do
245
243
  let(:server) { "server" }
246
244
 
247
245
  before do
246
+ allow(account).to receive(:"server=")
248
247
  allow(highline).to receive(:ask).with("server: ") { server }
249
248
 
250
249
  subject.run
@@ -253,16 +252,15 @@ describe Imap::Backup::Configuration::Account do
253
252
  end
254
253
 
255
254
  it "updates the server" do
256
- expect(account[:server]).to eq(server)
255
+ expect(account).to have_received(:"server=").with(server)
257
256
  end
258
-
259
- include_examples "it flags the account as modified"
260
257
  end
261
258
 
262
259
  describe "choosing 'modify backup path'" do
263
260
  let(:new_backup_path) { "/new/path" }
264
261
 
265
262
  before do
263
+ allow(account).to receive(:"local_path=")
266
264
  @validator = nil
267
265
  allow(
268
266
  Imap::Backup::Configuration::Asker
@@ -275,7 +273,7 @@ describe Imap::Backup::Configuration::Account do
275
273
  end
276
274
 
277
275
  it "updates the path" do
278
- expect(account[:local_path]).to eq(new_backup_path)
276
+ expect(account).to have_received(:"local_path=").with(new_backup_path)
279
277
  end
280
278
 
281
279
  context "when the path is not used by other backups" do
@@ -293,8 +291,6 @@ describe Imap::Backup::Configuration::Account do
293
291
  # rubocop:enable RSpec/InstanceVariable
294
292
  end
295
293
  end
296
-
297
- include_examples "it flags the account as modified"
298
294
  end
299
295
 
300
296
  describe "choosing 'choose backup folders'" do
@@ -333,6 +329,7 @@ describe Imap::Backup::Configuration::Account do
333
329
  let(:confirmed) { true }
334
330
 
335
331
  before do
332
+ allow(account).to receive(:mark_for_deletion!)
336
333
  allow(highline).to receive(:agree) { confirmed }
337
334
  subject.run
338
335
  catch :done do
@@ -345,13 +342,17 @@ describe Imap::Backup::Configuration::Account do
345
342
  end
346
343
 
347
344
  context "when the user confirms deletion" do
348
- include_examples "it flags the account to be deleted"
345
+ it "flags the account to be deleted" do
346
+ expect(account).to have_received(:mark_for_deletion!)
347
+ end
349
348
  end
350
349
 
351
350
  context "without confirmation" do
352
351
  let(:confirmed) { false }
353
352
 
354
- include_examples "it doesn't flag the account to be deleted"
353
+ it "doesn't flag the account to be deleted" do
354
+ expect(account).to_not have_received(:mark_for_deletion!)
355
+ end
355
356
  end
356
357
  end
357
358
  end
@@ -9,7 +9,14 @@ describe Imap::Backup::Configuration::FolderChooser do
9
9
  Imap::Backup::Account::Connection, folders: connection_folders
10
10
  )
11
11
  end
12
- let(:account) { {folders: []} }
12
+ let(:account) do
13
+ instance_double(
14
+ Imap::Backup::Account,
15
+ folders: account_folders,
16
+ "folders=": nil
17
+ )
18
+ end
19
+ let(:account_folders) { [] }
13
20
  let(:connection_folders) { [] }
14
21
  let!(:highline_streams) { prepare_highline }
15
22
  let(:input) { highline_streams[0] }
@@ -36,7 +43,7 @@ describe Imap::Backup::Configuration::FolderChooser do
36
43
  end
37
44
 
38
45
  describe "folder listing" do
39
- let(:account) { {folders: [{name: "my_folder"}]} }
46
+ let(:account_folders) { [{name: "my_folder"}]}
40
47
  let(:connection_folders) do
41
48
  # N.B. my_folder is already backed up
42
49
  %w(my_folder another_folder)
@@ -62,10 +69,9 @@ describe Imap::Backup::Configuration::FolderChooser do
62
69
  end
63
70
 
64
71
  specify "are added to the account" do
65
- expect(account[:folders]).to include(name: "another_folder")
72
+ expect(account).to have_received(:"folders=").
73
+ with([{name: "my_folder"}, {name: "another_folder"}])
66
74
  end
67
-
68
- include_examples "it flags the account as modified"
69
75
  end
70
76
 
71
77
  context "when removing folders" do
@@ -76,22 +82,16 @@ describe Imap::Backup::Configuration::FolderChooser do
76
82
  end
77
83
 
78
84
  specify "are removed from the account" do
79
- expect(account[:folders]).to_not include(name: "my_folder")
85
+ expect(account).to have_received(:"folders=").with([])
80
86
  end
81
-
82
- include_examples "it flags the account as modified"
83
87
  end
84
88
  end
85
89
 
86
90
  context "with missing remote folders" do
87
- let(:account) do
88
- {folders: [{name: "on_server"}, {name: "not_on_server"}]}
89
- end
90
- let(:connection_folders) do
91
- [
92
- instance_double(Imap::Backup::Account::Folder, name: "on_server")
93
- ]
91
+ let(:account_folders) do
92
+ [{name: "on_server"}, {name: "not_on_server"}]
94
93
  end
94
+ let(:connection_folders) { ["on_server"] }
95
95
 
96
96
  before do
97
97
  allow(Kernel).to receive(:puts)
@@ -99,10 +99,9 @@ describe Imap::Backup::Configuration::FolderChooser do
99
99
  end
100
100
 
101
101
  specify "are removed from the account" do
102
- expect(account[:folders]).to_not include(name: "not_on_server")
102
+ expect(account).to have_received(:"folders=").
103
+ with([{name: "on_server"}])
103
104
  end
104
-
105
- include_examples "it flags the account as modified"
106
105
  end
107
106
 
108
107
  context "when folders are not available" do
@@ -1,11 +1,18 @@
1
1
  describe Imap::Backup::Configuration::List do
2
2
  subject { described_class.new }
3
3
 
4
- let(:accounts) do
5
- [
6
- {username: "a1@example.com"},
7
- {username: "a2@example.com"}
8
- ]
4
+ let(:accounts) { [account1, account2] }
5
+ let(:account1) do
6
+ instance_double(
7
+ Imap::Backup::Account,
8
+ username: "a1@example.com"
9
+ )
10
+ end
11
+ let(:account2) do
12
+ instance_double(
13
+ Imap::Backup::Account,
14
+ username: "a2@example.com"
15
+ )
9
16
  end
10
17
  let(:store) do
11
18
  instance_double(Imap::Backup::Configuration::Store, accounts: accounts)