imap_guard 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitlab-ci.yml +16 -0
- data/.rspec +1 -1
- data/.rubocop.yml +46 -0
- data/Gemfile +14 -2
- data/Guardfile +4 -3
- data/LICENSE.txt +1 -1
- data/README.md +14 -17
- data/Rakefile +6 -2
- data/examples/example.rb +15 -13
- data/imap_guard.gemspec +12 -17
- data/lib/imap_guard/guard.rb +42 -42
- data/lib/imap_guard/query.rb +33 -32
- data/lib/imap_guard.rb +2 -0
- data/spec/imap_guard/guard_spec.rb +69 -68
- data/spec/imap_guard/query_spec.rb +26 -27
- data/spec/spec_helper.rb +5 -4
- metadata +20 -136
- data/.ruby-version +0 -1
- data/.travis.yml +0 -15
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ImapGuard
|
4
4
|
describe Guard do
|
@@ -12,21 +12,21 @@ module ImapGuard
|
|
12
12
|
|
13
13
|
let(:settings) do
|
14
14
|
{
|
15
|
-
host:
|
15
|
+
host: "localhost",
|
16
16
|
port: 993,
|
17
|
-
username:
|
18
|
-
password:
|
17
|
+
username: "bob",
|
18
|
+
password: "PASS",
|
19
19
|
}
|
20
20
|
end
|
21
21
|
|
22
22
|
let(:imap) do
|
23
|
-
|
23
|
+
instance_double(Net::IMAP, search: [7, 28], expunge: nil, select: nil, list: [])
|
24
24
|
end
|
25
25
|
|
26
|
-
def guard_instance
|
26
|
+
def guard_instance(custom_settings = {})
|
27
27
|
guard = Guard.new(settings.merge(custom_settings))
|
28
28
|
guard.instance_variable_set(:@imap, imap)
|
29
|
-
guard.
|
29
|
+
allow(guard).to receive(:fetch_mail)
|
30
30
|
guard
|
31
31
|
end
|
32
32
|
|
@@ -35,7 +35,7 @@ module ImapGuard
|
|
35
35
|
let(:guard) { guard_instance(read_only: true) }
|
36
36
|
|
37
37
|
it "opens the mailbox in read-only" do
|
38
|
-
imap.
|
38
|
+
expect(imap).to receive(:examine)
|
39
39
|
guard.select nil
|
40
40
|
end
|
41
41
|
end
|
@@ -44,7 +44,7 @@ module ImapGuard
|
|
44
44
|
let(:guard) { guard_instance(read_only: false) }
|
45
45
|
|
46
46
|
it "opens the mailbox in read-write" do
|
47
|
-
imap.
|
47
|
+
expect(imap).to receive(:select)
|
48
48
|
guard.select nil
|
49
49
|
end
|
50
50
|
end
|
@@ -52,46 +52,46 @@ module ImapGuard
|
|
52
52
|
|
53
53
|
describe "#mailbox" do
|
54
54
|
it "returns nil when no mailbox has been selected" do
|
55
|
-
guard_instance.mailbox.
|
55
|
+
expect(guard_instance.mailbox).to be_nil
|
56
56
|
end
|
57
57
|
|
58
58
|
it "returns the currently selected mailbox" do
|
59
59
|
guard = guard_instance
|
60
60
|
|
61
|
-
guard.select
|
62
|
-
guard.mailbox.
|
61
|
+
guard.select "Sent"
|
62
|
+
expect(guard.mailbox).to eq "Sent"
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
66
|
describe "#list" do
|
67
67
|
it "returns the list of mailboxes" do
|
68
|
-
imap.
|
69
|
-
guard_instance.list.
|
68
|
+
expect(imap).to receive(:list)
|
69
|
+
expect(guard_instance.list).to eq []
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
73
|
describe "#search" do
|
74
74
|
before do
|
75
|
-
imap.
|
76
|
-
[13, 37] if [[
|
75
|
+
expect(imap).to receive(:search) do |arg|
|
76
|
+
[13, 37] if [["ALL"], "ALL"].include? arg
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
80
|
it "accepts arrays" do
|
81
|
-
expect
|
82
|
-
guard_instance.send(:search, [
|
83
|
-
|
81
|
+
expect do
|
82
|
+
guard_instance.send(:search, ["ALL"])
|
83
|
+
end.not_to raise_error
|
84
84
|
end
|
85
85
|
|
86
86
|
it "accepts strings" do
|
87
|
-
expect
|
88
|
-
guard_instance.send(:search,
|
89
|
-
|
87
|
+
expect do
|
88
|
+
guard_instance.send(:search, "ALL")
|
89
|
+
end.not_to raise_error
|
90
90
|
end
|
91
91
|
|
92
92
|
it "returns results" do
|
93
|
-
messages = guard_instance.send(:search,
|
94
|
-
messages.
|
93
|
+
messages = guard_instance.send(:search, "ALL")
|
94
|
+
expect(messages).to eq [13, 37]
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
@@ -101,49 +101,49 @@ module ImapGuard
|
|
101
101
|
|
102
102
|
context "without a filter block" do
|
103
103
|
it "does perform the operation" do
|
104
|
-
opeartion.
|
105
|
-
opeartion.
|
104
|
+
expect(opeartion).to receive(:call).with(7)
|
105
|
+
expect(opeartion).to receive(:call).with(28)
|
106
106
|
|
107
|
-
guard.send(:process,
|
107
|
+
guard.send(:process, "ALL", opeartion)
|
108
108
|
end
|
109
109
|
|
110
110
|
it "does not execute the filter block" do
|
111
|
-
guard.
|
111
|
+
expect(guard).not_to receive(:fetch_mail)
|
112
112
|
|
113
|
-
guard.send(:process,
|
113
|
+
guard.send(:process, "ALL", opeartion)
|
114
114
|
end
|
115
115
|
|
116
116
|
context "with a debug proc" do
|
117
117
|
it "calls the proc" do
|
118
118
|
block = ->(mail) {}
|
119
119
|
guard.debug = block
|
120
|
-
block.
|
120
|
+
expect(block).to receive(:call).twice
|
121
121
|
|
122
|
-
guard.send(:process,
|
122
|
+
guard.send(:process, "ALL", opeartion)
|
123
123
|
end
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
127
|
context "with a filter block" do
|
128
128
|
it "executes the filter block" do
|
129
|
-
guard.
|
129
|
+
expect(guard).to receive(:fetch_mail).twice
|
130
130
|
|
131
|
-
guard.send(:process,
|
131
|
+
guard.send(:process, "ALL", opeartion) { nil }
|
132
132
|
end
|
133
133
|
|
134
|
-
context "returning false" do
|
134
|
+
context "when returning false" do
|
135
135
|
it "does not perform the operation" do
|
136
|
-
opeartion.
|
136
|
+
expect(opeartion).not_to receive(:call)
|
137
137
|
|
138
|
-
guard.send(:process,
|
138
|
+
guard.send(:process, "ALL", opeartion) { false }
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
142
|
-
context "returning true" do
|
142
|
+
context "when returning true" do
|
143
143
|
it "does perform the operation" do
|
144
|
-
opeartion.
|
144
|
+
expect(opeartion).to receive(:call).twice
|
145
145
|
|
146
|
-
guard.send(:process,
|
146
|
+
guard.send(:process, "ALL", opeartion) { true }
|
147
147
|
end
|
148
148
|
end
|
149
149
|
end
|
@@ -151,51 +151,53 @@ module ImapGuard
|
|
151
151
|
|
152
152
|
describe "#move" do
|
153
153
|
it "copies emails before adding the :Deleted flag" do
|
154
|
-
imap.
|
155
|
-
imap.
|
156
|
-
imap.
|
157
|
-
imap.
|
158
|
-
imap.
|
154
|
+
expect(imap).to receive(:search)
|
155
|
+
expect(imap).to receive(:copy).with(7, "destination").ordered
|
156
|
+
expect(imap).to receive(:store).with(7, "+FLAGS", [:Deleted]).ordered
|
157
|
+
expect(imap).to receive(:copy).with(28, "destination").ordered
|
158
|
+
expect(imap).to receive(:store).with(28, "+FLAGS", [:Deleted]).ordered
|
159
159
|
|
160
|
-
guard_instance.move
|
160
|
+
guard_instance.move "ALL", "destination"
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
164
164
|
describe "#delete" do
|
165
165
|
it "adds the :Deleted flag" do
|
166
|
-
imap.
|
167
|
-
imap.
|
168
|
-
imap.
|
166
|
+
expect(imap).to receive(:search)
|
167
|
+
expect(imap).to receive(:store).with(7, "+FLAGS", [:Deleted])
|
168
|
+
expect(imap).to receive(:store).with(28, "+FLAGS", [:Deleted])
|
169
169
|
|
170
|
-
guard_instance.delete
|
170
|
+
guard_instance.delete "ALL"
|
171
171
|
end
|
172
172
|
end
|
173
173
|
|
174
174
|
describe "#each" do
|
175
175
|
it "iterates over messages without errors" do
|
176
|
-
|
177
|
-
|
178
|
-
|
176
|
+
expect do
|
177
|
+
guard_instance.each "ALL" do |message_id|
|
178
|
+
# noop
|
179
|
+
end
|
180
|
+
end.not_to raise_error
|
179
181
|
end
|
180
182
|
end
|
181
183
|
|
182
184
|
describe "#expunge" do
|
183
185
|
it "expunges the folder" do
|
184
|
-
imap.
|
186
|
+
expect(imap).to receive(:expunge)
|
185
187
|
guard_instance.expunge
|
186
188
|
end
|
187
189
|
end
|
188
190
|
|
189
191
|
describe "#close" do
|
190
192
|
it "closes the IMAP connection" do
|
191
|
-
imap.
|
193
|
+
expect(imap).to receive(:close)
|
192
194
|
guard_instance.close
|
193
195
|
end
|
194
196
|
end
|
195
197
|
|
196
198
|
describe "#disconnect" do
|
197
199
|
it "disconnects from the server" do
|
198
|
-
imap.
|
200
|
+
expect(imap).to receive(:disconnect)
|
199
201
|
guard_instance.disconnect
|
200
202
|
end
|
201
203
|
end
|
@@ -205,7 +207,7 @@ module ImapGuard
|
|
205
207
|
let(:guard) { guard_instance(verbose: true) }
|
206
208
|
|
207
209
|
it "does output to $stdout" do
|
208
|
-
$stdout.
|
210
|
+
expect($stdout).to receive(:write).with("ham")
|
209
211
|
guard.send(:verbose).print "ham"
|
210
212
|
end
|
211
213
|
end
|
@@ -214,7 +216,7 @@ module ImapGuard
|
|
214
216
|
let(:guard) { guard_instance(verbose: false) }
|
215
217
|
|
216
218
|
it "does not output to $stdout" do
|
217
|
-
$stdout.
|
219
|
+
expect($stdout).not_to receive(:write)
|
218
220
|
guard.send(:verbose).print "ham"
|
219
221
|
end
|
220
222
|
end
|
@@ -222,27 +224,26 @@ module ImapGuard
|
|
222
224
|
|
223
225
|
describe "#settings=" do
|
224
226
|
it "freezes the settings" do
|
225
|
-
guard =
|
227
|
+
guard = described_class.new(settings)
|
226
228
|
|
227
229
|
exception = (RUBY_VERSION >= "2.1.0" ? RuntimeError : TypeError)
|
228
230
|
|
229
|
-
expect
|
230
|
-
guard.settings.host =
|
231
|
-
|
231
|
+
expect do
|
232
|
+
guard.settings.host = "example.net"
|
233
|
+
end.to raise_error(exception, /frozen/)
|
232
234
|
end
|
233
235
|
|
234
236
|
it "raises ArgumentError if any required key is missing" do
|
235
|
-
expect
|
236
|
-
|
237
|
-
|
237
|
+
expect do
|
238
|
+
described_class.new({})
|
239
|
+
end.to raise_error ArgumentError, /missing/i
|
238
240
|
end
|
239
241
|
|
240
242
|
it "raises ArgumentError if any key is unknown" do
|
241
|
-
expect
|
242
|
-
|
243
|
-
|
243
|
+
expect do
|
244
|
+
described_class.new(settings.merge(coffee: true))
|
245
|
+
end.to raise_error ArgumentError, /unknown/i
|
244
246
|
end
|
245
247
|
end
|
246
248
|
end
|
247
249
|
end
|
248
|
-
|
@@ -1,43 +1,43 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ImapGuard
|
4
4
|
describe Query do
|
5
5
|
describe "#initialize" do
|
6
|
-
it {
|
6
|
+
it { is_expected.to be_empty }
|
7
7
|
end
|
8
8
|
|
9
9
|
describe "#seen" do
|
10
10
|
it "adds 'SEEN'" do
|
11
11
|
subject.seen
|
12
|
-
subject.last.
|
12
|
+
expect(subject.last).to eq "SEEN"
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
describe "#unseen" do
|
17
17
|
it "adds 'UNSEEN'" do
|
18
18
|
subject.unseen
|
19
|
-
subject.last.
|
19
|
+
expect(subject.last).to eq "UNSEEN"
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
describe "#unanswered" do
|
24
24
|
it "adds 'UNANSWERED'" do
|
25
25
|
subject.unanswered
|
26
|
-
subject.last.
|
26
|
+
expect(subject.last).to eq "UNANSWERED"
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
describe "#unflagged" do
|
31
31
|
it "adds 'UNFLAGGED'" do
|
32
32
|
subject.unflagged
|
33
|
-
subject.last.
|
33
|
+
expect(subject.last).to eq "UNFLAGGED"
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
37
|
describe "#deleted" do
|
38
38
|
it "adds 'DELETED'" do
|
39
39
|
subject.deleted
|
40
|
-
subject.last.
|
40
|
+
expect(subject.last).to eq "DELETED"
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -45,26 +45,26 @@ module ImapGuard
|
|
45
45
|
context "without a search key" do
|
46
46
|
it "adds 'OR'" do
|
47
47
|
subject.or
|
48
|
-
subject.last.
|
48
|
+
expect(subject.last).to eq "OR"
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
context "with search keys" do
|
53
53
|
it "adds 'OR UNANSWERED UNFLAGGED '" do
|
54
54
|
subject.or(:unanswered, :unflagged)
|
55
|
-
subject.last(3).
|
55
|
+
expect(subject.last(3)).to eq %w[OR UNANSWERED UNFLAGGED]
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
context "with only one non-nil search key" do
|
60
60
|
it "raises ArgumentError" do
|
61
|
-
expect
|
61
|
+
expect do
|
62
62
|
subject.or(:whatever)
|
63
|
-
|
63
|
+
end.to raise_error(ArgumentError)
|
64
64
|
|
65
|
-
expect
|
65
|
+
expect do
|
66
66
|
subject.or(nil, :whatever)
|
67
|
-
|
67
|
+
end.to raise_error(ArgumentError)
|
68
68
|
end
|
69
69
|
end
|
70
70
|
end
|
@@ -72,28 +72,28 @@ module ImapGuard
|
|
72
72
|
describe "#subject" do
|
73
73
|
it "adds the search value" do
|
74
74
|
subject.subject("Hey you")
|
75
|
-
subject.last.
|
75
|
+
expect(subject.last).to eq "Hey you"
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
79
|
describe "#from" do
|
80
80
|
it "adds the search value" do
|
81
81
|
subject.from("root@example.net")
|
82
|
-
subject.last.
|
82
|
+
expect(subject.last).to eq "root@example.net"
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
86
|
describe "#to" do
|
87
87
|
it "adds the search value" do
|
88
88
|
subject.to("root@example.net")
|
89
|
-
subject.last.
|
89
|
+
expect(subject.last).to eq "root@example.net"
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
93
|
describe "#cc" do
|
94
94
|
it "adds the search value" do
|
95
95
|
subject.cc("root@example.net")
|
96
|
-
subject.last.
|
96
|
+
expect(subject.last).to eq "root@example.net"
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
@@ -101,14 +101,14 @@ module ImapGuard
|
|
101
101
|
context "without a search key" do
|
102
102
|
it "adds 'NOT'" do
|
103
103
|
subject.not.deleted
|
104
|
-
subject.last(2).
|
104
|
+
expect(subject.last(2)).to eq %w[NOT DELETED]
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
108
|
context "with a search key" do
|
109
109
|
it "adds 'NOT DELETED'" do
|
110
110
|
subject.not(:deleted)
|
111
|
-
subject.last(2).
|
111
|
+
expect(subject.last(2)).to eq %w[NOT DELETED]
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
@@ -116,40 +116,39 @@ module ImapGuard
|
|
116
116
|
describe "#before" do
|
117
117
|
context "when I pass 'nil' as an argument" do
|
118
118
|
it "raises" do
|
119
|
-
expect
|
119
|
+
expect do
|
120
120
|
subject.before(nil)
|
121
|
-
|
121
|
+
end.to raise_error ArgumentError
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
125
|
context "when I pass '1' as an argument" do
|
126
126
|
it "returns yesterday" do
|
127
127
|
subject.before(1)
|
128
|
-
Date.parse(subject.last).
|
128
|
+
expect(Date.parse(subject.last)).to eq Date.today.prev_day
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
132
|
context "when I pass an integer" do
|
133
133
|
it "uses it as a negative offset in days" do
|
134
134
|
subject.before(3)
|
135
|
-
(Date.today - Date.parse(subject.last)).
|
135
|
+
expect((Date.today - Date.parse(subject.last))).to eq 3
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
139
139
|
context "when I pass '18-Mar-2013' as an argument" do
|
140
140
|
it "uses it as is" do
|
141
|
-
subject.before(
|
142
|
-
subject.last.
|
141
|
+
subject.before("18-Mar-2013")
|
142
|
+
expect(subject.last).to eq "18-Mar-2013"
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
146
|
context "when I pass an instance of Date as an argument" do
|
147
147
|
it "extracts the date" do
|
148
148
|
subject.before(Date.today)
|
149
|
-
Date.parse(subject.last).
|
149
|
+
expect(Date.parse(subject.last)).to eq Date.today
|
150
150
|
end
|
151
151
|
end
|
152
152
|
end
|
153
153
|
end
|
154
154
|
end
|
155
|
-
|
data/spec/spec_helper.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "simplecov"
|
2
4
|
SimpleCov.start do
|
3
|
-
minimum_coverage
|
5
|
+
minimum_coverage 95
|
4
6
|
add_group "Sources", "lib"
|
5
7
|
add_group "Tests", "spec"
|
6
8
|
end
|
7
9
|
|
8
|
-
require
|
10
|
+
require "imap_guard"
|
9
11
|
|
10
12
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |file| require file }
|
11
|
-
|