imap-backup 2.1.1 → 2.2.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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/README.md +6 -2
  4. data/bin/imap-backup +1 -1
  5. data/lib/email/mboxrd/message.rb +0 -1
  6. data/lib/imap/backup/account/connection.rb +28 -21
  7. data/lib/imap/backup/account/folder.rb +0 -1
  8. data/lib/imap/backup/serializer/mbox_enumerator.rb +1 -1
  9. data/lib/imap/backup/uploader.rb +10 -1
  10. data/lib/imap/backup/version.rb +2 -2
  11. data/spec/features/restore_spec.rb +75 -27
  12. data/spec/features/support/email_server.rb +1 -3
  13. data/spec/features/support/shared/message_fixtures.rb +8 -0
  14. data/spec/unit/email/mboxrd/message_spec.rb +0 -6
  15. data/spec/unit/imap/backup/account/connection_spec.rb +58 -43
  16. data/spec/unit/imap/backup/account/folder_spec.rb +16 -20
  17. data/spec/unit/imap/backup/configuration/account_spec.rb +31 -25
  18. data/spec/unit/imap/backup/configuration/asker_spec.rb +20 -17
  19. data/spec/unit/imap/backup/configuration/connection_tester_spec.rb +6 -10
  20. data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +16 -10
  21. data/spec/unit/imap/backup/configuration/list_spec.rb +6 -3
  22. data/spec/unit/imap/backup/configuration/setup_spec.rb +40 -25
  23. data/spec/unit/imap/backup/configuration/store_spec.rb +18 -16
  24. data/spec/unit/imap/backup/downloader_spec.rb +14 -14
  25. data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +6 -1
  26. data/spec/unit/imap/backup/serializer/mbox_spec.rb +54 -40
  27. data/spec/unit/imap/backup/serializer/mbox_store_spec.rb +49 -31
  28. data/spec/unit/imap/backup/uploader_spec.rb +20 -7
  29. data/spec/unit/imap/backup/utils_spec.rb +8 -9
  30. metadata +2 -2
@@ -28,7 +28,7 @@ describe Imap::Backup::Account::Folder do
28
28
  describe "#uids" do
29
29
  let(:uids) { [5678, 123] }
30
30
 
31
- before { allow(imap).to receive(:uid_search).and_return(uids) }
31
+ before { allow(imap).to receive(:uid_search) { uids } }
32
32
 
33
33
  it "lists available messages" do
34
34
  expect(subject.uids).to eq(uids.reverse)
@@ -83,12 +83,6 @@ describe Imap::Backup::Account::Folder do
83
83
  expect(subject.fetch(123)).to be_nil
84
84
  end
85
85
  end
86
-
87
- it "sets the encoding on the message" do
88
- subject.fetch(123)
89
-
90
- expect(message_body).to have_received(:force_encoding).with("utf-8")
91
- end
92
86
  end
93
87
 
94
88
  describe "#folder" do
@@ -117,21 +111,22 @@ describe Imap::Backup::Account::Folder do
117
111
 
118
112
  describe "#create" do
119
113
  context "when the folder exists" do
120
- before { subject.create }
121
-
122
114
  it "is does not create the folder" do
123
- expect(imap).to_not have_received(:create)
115
+ expect(imap).to_not receive(:create)
116
+
117
+ subject.create
124
118
  end
125
119
  end
126
120
 
127
121
  context "when the folder doesn't exist" do
128
122
  before do
129
123
  allow(imap).to receive(:examine).and_raise(missing_mailbox_error)
130
- subject.create
131
124
  end
132
125
 
133
126
  it "is does not create the folder" do
134
- expect(imap).to have_received(:create)
127
+ expect(imap).to receive(:create)
128
+
129
+ subject.create
135
130
  end
136
131
  end
137
132
  end
@@ -168,26 +163,27 @@ describe Imap::Backup::Account::Folder do
168
163
  let(:append_response) do
169
164
  OpenStruct.new(data: OpenStruct.new(code: OpenStruct.new(data: "1 2")))
170
165
  end
171
- let(:result) { subject.append(message) }
172
-
173
- before do
174
- result
175
- end
176
166
 
177
167
  it "appends the message" do
178
- expect(imap).to have_received(:append)
168
+ expect(imap).to receive(:append)
169
+
170
+ subject.append(message)
179
171
  end
180
172
 
181
173
  it "sets the date and time" do
182
- expect(imap).to have_received(:append).
174
+ expect(imap).to receive(:append).
183
175
  with(anything, anything, anything, message_date)
176
+
177
+ subject.append(message)
184
178
  end
185
179
 
186
180
  it "returns the new uid" do
187
- expect(result).to eq(2)
181
+ expect(subject.append(message)).to eq(2)
188
182
  end
189
183
 
190
184
  it "set the new uid validity" do
185
+ subject.append(message)
186
+
191
187
  expect(subject.uid_validity).to eq(1)
192
188
  end
193
189
  end
@@ -1,23 +1,6 @@
1
1
  # rubocop:disable RSpec/NestedGroups
2
2
 
3
3
  describe Imap::Backup::Configuration::Account do
4
- class MockHighlineMenu
5
- attr_reader :choices
6
- attr_accessor :header
7
-
8
- def initialize
9
- @choices = {}
10
- end
11
-
12
- def choice(name, &block)
13
- choices[name] = block
14
- end
15
-
16
- def hidden(name, &block)
17
- choices[name] = block
18
- end
19
- end
20
-
21
4
  describe "#initialize" do
22
5
  subject { described_class.new(store, account, highline) }
23
6
 
@@ -35,8 +18,27 @@ describe Imap::Backup::Configuration::Account do
35
18
  describe "#run" do
36
19
  subject { described_class.new(store, account, highline) }
37
20
 
21
+ let(:highline_menu_class) do
22
+ Class.new do
23
+ attr_reader :choices
24
+ attr_accessor :header
25
+
26
+ def initialize
27
+ @choices = {}
28
+ end
29
+
30
+ def choice(name, &block)
31
+ choices[name] = block
32
+ end
33
+
34
+ def hidden(name, &block)
35
+ choices[name] = block
36
+ end
37
+ end
38
+ end
39
+
38
40
  let(:highline) { instance_double(HighLine) }
39
- let(:menu) { MockHighlineMenu.new }
41
+ let(:menu) { highline_menu_class.new }
40
42
  let(:store) do
41
43
  instance_double(Imap::Backup::Configuration::Store, accounts: accounts)
42
44
  end
@@ -73,15 +75,17 @@ describe Imap::Backup::Configuration::Account do
73
75
  end
74
76
 
75
77
  describe "preparation" do
76
- before { subject.run }
77
-
78
78
  it "clears the screen" do
79
- expect(Kernel).to have_received(:system).with("clear")
79
+ expect(Kernel).to receive(:system).with("clear")
80
+
81
+ subject.run
80
82
  end
81
83
 
82
84
  describe "menu" do
83
85
  it "shows the menu" do
84
- expect(highline).to have_received(:choose)
86
+ expect(highline).to receive(:choose)
87
+
88
+ subject.run
85
89
  end
86
90
  end
87
91
  end
@@ -240,8 +244,10 @@ describe Imap::Backup::Configuration::Account do
240
244
  let(:server) { "server" }
241
245
 
242
246
  before do
243
- allow(highline).to receive(:ask).with("server: ").and_return(server)
247
+ allow(highline).to receive(:ask).with("server: ") { server }
248
+
244
249
  subject.run
250
+
245
251
  menu.choices["modify server"].call
246
252
  end
247
253
 
@@ -310,7 +316,7 @@ describe Imap::Backup::Configuration::Account do
310
316
  describe "connection test" do
311
317
  before do
312
318
  allow(Imap::Backup::Configuration::ConnectionTester).
313
- to receive(:test).and_return("All fine")
319
+ to receive(:test) { "All fine" }
314
320
  allow(highline).to receive(:ask)
315
321
  subject.run
316
322
  menu.choices["test connection"].call
@@ -326,7 +332,7 @@ describe Imap::Backup::Configuration::Account do
326
332
  let(:confirmed) { true }
327
333
 
328
334
  before do
329
- allow(highline).to receive(:agree).and_return(confirmed)
335
+ allow(highline).to receive(:agree) { confirmed }
330
336
  subject.run
331
337
  catch :done do
332
338
  menu.choices["delete"].call
@@ -30,9 +30,9 @@ module Imap::Backup
30
30
  ].each do |method, params, prompt|
31
31
  context ".#{method}" do
32
32
  it "asks for input" do
33
- described_class.send(method, *params)
33
+ expect(highline).to receive(:ask).with("#{prompt}: ")
34
34
 
35
- expect(highline).to have_received(:ask).with("#{prompt}: ")
35
+ described_class.send(method, *params)
36
36
  end
37
37
 
38
38
  it "returns the answer" do
@@ -56,16 +56,15 @@ module Imap::Backup
56
56
  describe "#email" do
57
57
  let(:email) { "email@example.com" }
58
58
  let(:answer) { email }
59
- let(:result) { subject.email }
60
-
61
- before { result }
62
59
 
63
60
  it "asks for an email" do
64
- expect(highline).to have_received(:ask).with(/email/)
61
+ expect(highline).to receive(:ask).with(/email/)
62
+
63
+ subject.email
65
64
  end
66
65
 
67
66
  it "returns the address" do
68
- expect(result).to eq(email)
67
+ expect(subject.email).to eq(email)
69
68
  end
70
69
  end
71
70
 
@@ -73,7 +72,6 @@ module Imap::Backup
73
72
  let(:password1) { "password" }
74
73
  let(:password2) { "password" }
75
74
  let(:answers) { [true, false] }
76
- let(:result) { subject.password }
77
75
 
78
76
  before do
79
77
  i = 0
@@ -84,27 +82,32 @@ module Imap::Backup
84
82
  i += 1
85
83
  answer
86
84
  end
87
- result
88
85
  end
89
86
 
90
87
  it "asks for a password" do
91
- expect(highline).to have_received(:ask).with("password: ")
88
+ expect(highline).to receive(:ask).with("password: ")
89
+
90
+ subject.password
92
91
  end
93
92
 
94
93
  it "asks for confirmation" do
95
- expect(highline).to have_received(:ask).with("repeat password: ")
94
+ expect(highline).to receive(:ask).with("repeat password: ")
95
+
96
+ subject.password
96
97
  end
97
98
 
98
99
  it "returns the password" do
99
- expect(result).to eq(password1)
100
+ expect(subject.password).to eq(password1)
100
101
  end
101
102
 
102
103
  context "with different answers" do
103
104
  let(:password2) { "secret" }
104
105
 
105
106
  it "asks to continue" do
106
- expect(highline).to have_received(:agree).
107
+ expect(highline).to receive(:agree).
107
108
  at_least(:once).with(/Continue\?/)
109
+
110
+ subject.password
108
111
  end
109
112
  end
110
113
  end
@@ -112,22 +115,22 @@ module Imap::Backup
112
115
  describe "#backup_path" do
113
116
  let(:path) { "/path" }
114
117
  let(:answer) { path }
115
- let(:result) { subject.backup_path("", //) }
116
118
 
117
119
  before do
118
120
  allow(highline).to receive(:ask) do |&b|
119
121
  b.call query
120
122
  path
121
123
  end
122
- result
123
124
  end
124
125
 
125
126
  it "asks for a directory" do
126
- expect(highline).to have_received(:ask).with(/directory/)
127
+ expect(highline).to receive(:ask).with(/directory/)
128
+
129
+ subject.backup_path("", //)
127
130
  end
128
131
 
129
132
  it "returns the path" do
130
- expect(result).to eq(path)
133
+ expect(subject.backup_path("", //)).to eq(path)
131
134
  end
132
135
  end
133
136
  end
@@ -3,32 +3,28 @@ describe Imap::Backup::Configuration::ConnectionTester do
3
3
  let(:connection) do
4
4
  instance_double(Imap::Backup::Account::Connection, imap: nil)
5
5
  end
6
- let(:result) { subject.test("foo") }
7
6
 
8
7
  before do
9
8
  allow(Imap::Backup::Account::Connection).to receive(:new) { connection }
10
9
  end
11
10
 
12
11
  describe "call" do
13
- before { result }
14
-
15
12
  it "tries to connect" do
16
- expect(connection).to have_received(:imap)
13
+ expect(connection).to receive(:imap)
14
+
15
+ subject.test("foo")
17
16
  end
18
17
  end
19
18
 
20
19
  describe "success" do
21
- before { result }
22
-
23
20
  it "returns success" do
24
- expect(result).to match(/successful/)
21
+ expect(subject.test("foo")).to match(/successful/)
25
22
  end
26
23
  end
27
24
 
28
25
  describe "failure" do
29
26
  before do
30
27
  allow(connection).to receive(:imap).and_raise(error)
31
- result
32
28
  end
33
29
 
34
30
  context "with no connection" do
@@ -39,7 +35,7 @@ describe Imap::Backup::Configuration::ConnectionTester do
39
35
  end
40
36
 
41
37
  it "returns error" do
42
- expect(result).to match(/no response/i)
38
+ expect(subject.test("foo")).to match(/no response/i)
43
39
  end
44
40
  end
45
41
 
@@ -47,7 +43,7 @@ describe Imap::Backup::Configuration::ConnectionTester do
47
43
  let(:error) { "Error" }
48
44
 
49
45
  it "returns error" do
50
- expect(result).to match(/unexpected error/i)
46
+ expect(subject.test("foo")).to match(/unexpected error/i)
51
47
  end
52
48
  end
53
49
  end
@@ -22,13 +22,15 @@ describe Imap::Backup::Configuration::FolderChooser do
22
22
  end
23
23
 
24
24
  describe "display" do
25
- before { subject.run }
26
-
27
25
  it "clears the screen" do
28
- expect(Kernel).to have_received(:system).with("clear")
26
+ expect(Kernel).to receive(:system).with("clear")
27
+
28
+ subject.run
29
29
  end
30
30
 
31
31
  it "shows the menu" do
32
+ subject.run
33
+
32
34
  expect(output.string).to match %r{Add/remove folders}
33
35
  end
34
36
  end
@@ -114,13 +116,14 @@ describe Imap::Backup::Configuration::FolderChooser do
114
116
 
115
117
  before do
116
118
  allow(Imap::Backup::Configuration::Setup.highline).
117
- to receive(:ask).and_return("q")
118
- subject.run
119
+ to receive(:ask) { "q" }
119
120
  end
120
121
 
121
122
  it "asks to press a key" do
122
123
  expect(Imap::Backup::Configuration::Setup.highline).
123
- to have_received(:ask).with("Press a key ")
124
+ to receive(:ask).with("Press a key ")
125
+
126
+ subject.run
124
127
  end
125
128
  end
126
129
 
@@ -129,18 +132,21 @@ describe Imap::Backup::Configuration::FolderChooser do
129
132
  allow(Imap::Backup::Account::Connection).
130
133
  to receive(:new).with(account).and_raise("error")
131
134
  allow(Imap::Backup::Configuration::Setup.highline).
132
- to receive(:ask).and_return("q")
133
- subject.run
135
+ to receive(:ask) { "q" }
134
136
  end
135
137
 
136
138
  it "prints an error message" do
137
139
  expect(Imap::Backup.logger).
138
- to have_received(:warn).with("Connection failed")
140
+ to receive(:warn).with("Connection failed")
141
+
142
+ subject.run
139
143
  end
140
144
 
141
145
  it "asks to continue" do
142
146
  expect(Imap::Backup::Configuration::Setup.highline).
143
- to have_received(:ask).with("Press a key ")
147
+ to receive(:ask).with("Press a key ")
148
+
149
+ subject.run
144
150
  end
145
151
  end
146
152
  end
@@ -35,18 +35,21 @@ describe Imap::Backup::Configuration::List do
35
35
  allow(Imap::Backup::Configuration::Store).
36
36
  to receive(:exist?) { config_exists }
37
37
  allow(Imap::Backup).to receive(:setup_logging)
38
- subject.setup_logging
39
38
  end
40
39
 
41
40
  it "sets global logging level" do
42
- expect(Imap::Backup).to have_received(:setup_logging).with(store)
41
+ expect(Imap::Backup).to receive(:setup_logging).with(store)
42
+
43
+ subject.setup_logging
43
44
  end
44
45
 
45
46
  context "without a config" do
46
47
  let(:config_exists) { false }
47
48
 
48
49
  it "does nothing" do
49
- expect(Imap::Backup).to_not have_received(:setup_logging).with(store)
50
+ expect(Imap::Backup).to_not receive(:setup_logging).with(store)
51
+
52
+ subject.setup_logging
50
53
  end
51
54
  end
52
55
  end
@@ -52,15 +52,15 @@ describe Imap::Backup::Configuration::Setup do
52
52
  end
53
53
 
54
54
  it "clears the screen" do
55
- subject.run
55
+ expect(Kernel).to receive(:system).with("clear")
56
56
 
57
- expect(Kernel).to have_received(:system).with("clear")
57
+ subject.run
58
58
  end
59
59
 
60
60
  it "updates logging status" do
61
- subject.run
61
+ expect(Imap::Backup).to receive(:setup_logging)
62
62
 
63
- expect(Imap::Backup).to have_received(:setup_logging)
63
+ subject.run
64
64
  end
65
65
 
66
66
  describe "listing" do
@@ -97,15 +97,15 @@ describe Imap::Backup::Configuration::Setup do
97
97
  before do
98
98
  allow(input).to receive(:gets).and_return("1\n", "exit\n")
99
99
  allow(Imap::Backup::Configuration::Asker).to receive(:email).
100
- with(no_args).and_return("new@example.com")
100
+ with(no_args) { "new@example.com" }
101
101
  allow(Imap::Backup::Configuration::Account).to receive(:new).
102
- with(store, normal, anything).and_return(account)
103
-
104
- subject.run
102
+ with(store, normal, anything) { account }
105
103
  end
106
104
 
107
105
  it "edits the account" do
108
- expect(account).to have_received(:run)
106
+ expect(account).to receive(:run)
107
+
108
+ subject.run
109
109
  end
110
110
  end
111
111
 
@@ -125,9 +125,9 @@ describe Imap::Backup::Configuration::Setup do
125
125
  before do
126
126
  allow(input).to receive(:gets).and_return("add\n", "exit\n")
127
127
  allow(Imap::Backup::Configuration::Asker).to receive(:email).
128
- with(no_args).and_return("new@example.com")
128
+ with(no_args) { "new@example.com" }
129
129
  allow(Imap::Backup::Configuration::Account).to receive(:new).
130
- with(store, blank_account, anything).and_return(account)
130
+ with(store, blank_account, anything) { account }
131
131
 
132
132
  subject.run
133
133
  end
@@ -145,20 +145,25 @@ describe Imap::Backup::Configuration::Setup do
145
145
  context "when debug logging is disabled" do
146
146
  before do
147
147
  allow(input).to receive(:gets).and_return("start\n", "exit\n")
148
- subject.run
149
148
  end
150
149
 
151
150
  it "shows a menu item" do
151
+ subject.run
152
+
152
153
  expect(output.string).to include("start logging")
153
154
  end
154
155
 
155
156
  context "when selected" do
156
157
  it "sets the debug flag" do
157
- expect(store).to have_received(:debug=).with(true)
158
+ expect(store).to receive(:debug=).with(true)
159
+
160
+ subject.run
158
161
  end
159
162
 
160
163
  it "updates logging status" do
161
- expect(Imap::Backup).to have_received(:setup_logging).twice
164
+ expect(Imap::Backup).to receive(:setup_logging).twice
165
+
166
+ subject.run
162
167
  end
163
168
  end
164
169
  end
@@ -168,10 +173,11 @@ describe Imap::Backup::Configuration::Setup do
168
173
 
169
174
  before do
170
175
  allow(input).to receive(:gets).and_return("stop\n", "exit\n")
171
- subject.run
172
176
  end
173
177
 
174
178
  it "shows a menu item" do
179
+ subject.run
180
+
175
181
  expect(output.string).to include("stop logging")
176
182
  end
177
183
 
@@ -181,11 +187,15 @@ describe Imap::Backup::Configuration::Setup do
181
187
  end
182
188
 
183
189
  it "unsets the debug flag" do
184
- expect(store).to have_received(:debug=).with(false)
190
+ expect(store).to receive(:debug=).with(false)
191
+
192
+ subject.run
185
193
  end
186
194
 
187
195
  it "updates logging status" do
188
- expect(Imap::Backup).to have_received(:setup_logging).twice
196
+ expect(Imap::Backup).to receive(:setup_logging).twice
197
+
198
+ subject.run
189
199
  end
190
200
  end
191
201
  end
@@ -193,41 +203,46 @@ describe Imap::Backup::Configuration::Setup do
193
203
 
194
204
  context "when 'save' is selected" do
195
205
  before do
196
- allow(input).to receive(:gets).and_return("save\n")
197
- subject.run
206
+ allow(input).to receive(:gets) { "save\n" }
198
207
  end
199
208
 
200
209
  it "exits" do
201
210
  # N.B. this will hang forever if save does not cause an exit
211
+ subject.run
202
212
  end
203
213
 
204
214
  it "saves the configuration" do
205
- expect(store).to have_received(:save)
215
+ expect(store).to receive(:save)
216
+
217
+ subject.run
206
218
  end
207
219
  end
208
220
 
209
221
  context "when 'exit without saving' is selected" do
210
222
  before do
211
- allow(input).to receive(:gets).and_return("exit\n")
212
-
213
- subject.run
223
+ allow(input).to receive(:gets) { "exit\n" }
214
224
  end
215
225
 
216
226
  it "exits" do
217
227
  # N.B. this will hang forever if quit does not cause an exit
228
+ subject.run
218
229
  end
219
230
 
220
231
  context "when the configuration is modified" do
221
232
  let(:modified) { true }
222
233
 
223
234
  it "doesn't save the configuration" do
224
- expect(store).to_not have_received(:save)
235
+ expect(store).to_not receive(:save)
236
+
237
+ subject.run
225
238
  end
226
239
  end
227
240
 
228
241
  context "when the configuration isn't modified" do
229
242
  it "doesn't save the configuration" do
230
- expect(store).to_not have_received(:save)
243
+ expect(store).to_not receive(:save)
244
+
245
+ subject.run
231
246
  end
232
247
  end
233
248
  end