rims 0.2.6 → 0.3.1

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.
@@ -23,11 +23,6 @@ module RIMS::Test
23
23
  end
24
24
  private :add_msg
25
25
 
26
- def get_msg_flag(uid, flag_name)
27
- @mail_store.msg_flag(@inbox_id, uid, flag_name)
28
- end
29
- private :get_msg_flag
30
-
31
26
  def set_msg_flag(uid, flag_name, flag_value)
32
27
  @mail_store.set_msg_flag(@inbox_id, uid, flag_name, flag_value)
33
28
  nil
@@ -48,14 +43,8 @@ module RIMS::Test
48
43
  end
49
44
  private :assert_msg_uid
50
45
 
51
- def assert_msg_flag(flag_name, *flag_value_list)
52
- uid_list = @mail_store.each_msg_uid(@inbox_id).to_a
53
- assert_equal(uid_list.map{|uid| get_msg_flag(uid, flag_name) }, flag_value_list)
54
- end
55
- private :assert_msg_flag
56
-
57
46
  def make_search_parser(charset: nil)
58
- yield
47
+ yield if block_given?
59
48
  @folder = @mail_store.open_folder(@inbox_id, read_only: true).reload
60
49
  @parser = RIMS::Protocol::SearchParser.new(@mail_store, @folder)
61
50
  @parser.charset = charset if charset
@@ -73,8 +62,8 @@ module RIMS::Test
73
62
  end
74
63
  private :parse_search_key
75
64
 
76
- def assert_search_cond(msg_idx, expected_found_flag)
77
- assert_equal(expected_found_flag, @cond.call(@folder[msg_idx]))
65
+ def assert_search_cond(msg_idx, expected_found_flag, *optional)
66
+ assert_equal(expected_found_flag, @cond.call(@folder[msg_idx]), *optional)
78
67
  end
79
68
  private :assert_search_cond
80
69
 
@@ -93,86 +82,125 @@ module RIMS::Test
93
82
  end
94
83
  private :assert_search_syntax_error
95
84
 
96
- def test_parse_all
97
- make_search_parser{
98
- add_msg('foo')
99
- assert_msg_uid(1)
100
- }
101
-
102
- parse_search_key([ 'ALL' ]) {
103
- assert_search_cond(0, true)
104
- }
105
- end
106
-
107
- def test_parse_answered
108
- make_search_parser{
109
- add_msg('foo')
110
- add_msg('foo')
111
- assert_msg_uid(1, 2)
112
-
113
- set_msg_flag(1, 'answered', true)
114
- assert_msg_flag('answered', true, false)
115
- }
116
-
117
- parse_search_key([ 'ANSWERED' ]) {
118
- assert_search_cond(0, true)
119
- assert_search_cond(1, false)
120
- }
121
- end
122
-
123
- def test_parse_bcc
124
- make_search_parser{
125
- add_msg("Bcc: foo\r\n" +
126
- "\r\n" +
127
- "foo")
128
- add_msg("Bcc: bar\r\n" +
129
- "\r\n" +
130
- "foo")
131
- add_msg('foo')
132
- assert_msg_uid(1, 2, 3)
133
- }
134
-
135
- parse_search_key([ 'BCC', 'foo' ]) {
136
- assert_search_cond(0, true)
137
- assert_search_cond(1, false)
138
- assert_search_cond(2, false)
139
- }
140
-
141
- assert_search_syntax_error([ 'BCC' ], /need for a search string/)
142
- assert_search_syntax_error([ 'BCC', [ :group, 'foo' ] ], /search string expected as <String> but was/)
143
- end
144
-
145
- def test_parse_before
146
- make_search_parser{
147
- add_msg('foo', Time.parse('2013-11-07 12:34:56'))
148
- add_msg('foo', Time.parse('2013-11-08 12:34:56'))
149
- add_msg('foo', Time.parse('2013-11-09 12:34:56'))
150
- assert_msg_uid(1, 2, 3)
151
- }
152
-
153
- parse_search_key([ 'BEFORE', '08-Nov-2013' ]) {
154
- assert_search_cond(0, true)
155
- assert_search_cond(1, false)
156
- assert_search_cond(2, false)
157
- }
158
-
159
- assert_search_syntax_error([ 'BEFORE' ], /need for a search date/)
160
- assert_search_syntax_error([ 'BEFORE', '99-Nov-2013' ], /search date is invalid/)
161
- assert_search_syntax_error([ 'BEFORE', [ :group, '08-Nov-2013'] ], /search date string expected as <String> but was/)
162
- end
163
-
164
- def test_parse_body
165
- make_search_parser{
166
- add_msg("Content-Type: text/plain\r\n" +
167
- "\r\n" +
168
- "foo")
169
- add_msg("Content-Type: text/plain\r\n" +
170
- "\r\n" +
171
- "bar")
172
- add_msg("Content-Type: message/rfc822\r\n" +
173
- "\r\n" +
174
- "foo")
175
- add_msg(<<-'EOF')
85
+ # test data format:
86
+ # { search: <search key array>,
87
+ # charset: <charset (optional)>,
88
+ # messages: [
89
+ # [ <expected search condition>,
90
+ # <message text>,
91
+ # <message flags>,
92
+ # (<optional arguments for `RIMS::MailStore#add_msg'>)
93
+ # ],
94
+ # ...
95
+ # ]
96
+ # }
97
+ data('ALL', {
98
+ search: %w[ ALL ],
99
+ messages: [
100
+ [ true, 'foo', {} ]
101
+ ]
102
+ })
103
+ [ [ 'ANSWERED', %w[ ANSWERED ], [ true, false ] ],
104
+ [ 'UNANSWERED', %w[ UNANSWERED ], [ false, true ] ]
105
+ ].each do |label, search, cond_list|
106
+ data(label, {
107
+ search: search,
108
+ messages: [
109
+ [ ' foo', { answered: true } ],
110
+ [ 'foo', { answered: false } ]
111
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
112
+ })
113
+ end
114
+ [ [ 'us-ascii', %w[ BCC foo ], [ true, true, false, false, false, false, false, false ] ],
115
+ [ 'charset', %W[ BCC \u306F\u306B\u307B ], [ false, false, false, false, true, false, true, false ], 'utf-8' ]
116
+ ].each do |label, search, cond_list, charset|
117
+ data("BCC:#{label}", {
118
+ search: search,
119
+ charset: charset,
120
+ messages: [
121
+ [ "Bcc: foo\r\n" +
122
+ "\r\n" +
123
+ "foo",
124
+ {}
125
+ ],
126
+ [ "Bcc: FOO\r\n" +
127
+ "\r\n" +
128
+ "foo",
129
+ {}
130
+ ],
131
+ [ "Bcc: bar\r\n" +
132
+ "\r\n" +
133
+ "foo",
134
+ {},
135
+ ],
136
+ [ 'foo',
137
+ {}
138
+ ],
139
+ [ "Bcc: =?UTF-8?B?44GE44KN44Gv44Gr44G744G444Go?=\r\n" +
140
+ "\r\n" +
141
+ "foo",
142
+ {},
143
+ ],
144
+ [ "Bcc: =?UTF-8?B?44Gh44KK44Gs44KL44KS?=\r\n" +
145
+ "\r\n" +
146
+ "foo",
147
+ {}
148
+ ],
149
+ [ "Bcc: =?ISO-2022-JP?B?GyRCJCQkbSRPJEskWyRYJEgbKEI=?=\r\n" +
150
+ "\r\n" +
151
+ "foo",
152
+ {},
153
+ ],
154
+ [ "Bcc: =?ISO-2022-JP?B?GyRCJEEkaiRMJGskchsoQg==?=\r\n" +
155
+ "\r\n" +
156
+ "foo",
157
+ {},
158
+ ]
159
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
160
+ })
161
+ end
162
+ [ [ 'BEFORE', %w[ BEFORE 08-Nov-2013 ], [ true, false, false ] ],
163
+ [ 'ON', %w[ ON 08-Nov-2013 ], [ false, true, false ] ],
164
+ [ 'SINCE', %w[ SINCE 08-Nov-2013 ], [ false, false, true ] ]
165
+ ].each do |label, search, cond_list|
166
+ data(label, {
167
+ search: search,
168
+ messages: [
169
+ [ 'foo', {}, Time.parse('2013-11-07 12:34:56 +0000') ],
170
+ [ 'foo', {}, Time.parse('2013-11-08 12:34:56 +0000') ],
171
+ [ 'foo', {}, Time.parse('2013-11-09 12:34:56 +0000') ]
172
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
173
+ })
174
+ end
175
+ data('BODY', {
176
+ search: %w[ BODY foo ],
177
+ messages: [
178
+ [ true,
179
+ "Content-Type: text/plain\r\n" +
180
+ "\r\n" +
181
+ "foo",
182
+ {}
183
+ ],
184
+ [ true,
185
+ "Content-Type: text/plain\r\n" +
186
+ "\r\n" +
187
+ "FOO",
188
+ {}
189
+ ],
190
+ [ false,
191
+ "Content-Type: text/plain\r\n" +
192
+ "\r\n" +
193
+ "bar",
194
+ {}
195
+ ],
196
+ [ true,
197
+ "Content-Type: message/rfc822\r\n" +
198
+ "\r\n" +
199
+ "foo",
200
+ {}
201
+ ],
202
+ [ true,
203
+ <<-'EOF',
176
204
  Content-Type: multipart/alternative; boundary="1383.905529.351297"
177
205
 
178
206
  --1383.905529.351297
@@ -184,543 +212,652 @@ Content-Type: text/html
184
212
 
185
213
  <html><body><p>foo</p></body></html>
186
214
  --1383.905529.351297--
187
- EOF
188
-
189
- assert_msg_uid(1, 2, 3, 4)
190
- }
191
-
192
- parse_search_key([ 'BODY', 'foo' ]) {
193
- assert_search_cond(0, true)
194
- assert_search_cond(1, false)
195
- assert_search_cond(2, true)
196
- assert_search_cond(3, false) # ignored text part of multipart message.
197
- }
198
-
199
- assert_search_syntax_error([ 'BODY' ], /need for a search string/)
200
- assert_search_syntax_error([ 'BODY', [ :group, 'foo' ] ], /search string expected as <String> but was/)
201
- end
202
-
203
- def test_parse_cc
204
- make_search_parser{
205
- add_msg("Cc: foo\r\n" +
206
- "\r\n" +
207
- "foo")
208
- add_msg("Cc: bar\r\n" +
209
- "\r\n" +
210
- "foo")
211
- add_msg('foo')
212
- assert_msg_uid(1, 2, 3)
213
- }
214
-
215
- parse_search_key([ 'CC', 'foo' ]) {
216
- assert_search_cond(0, true)
217
- assert_search_cond(1, false)
218
- assert_search_cond(2, false)
219
- }
220
-
221
- assert_search_syntax_error([ 'CC' ], /need for a search string/)
222
- assert_search_syntax_error([ 'CC', [ :group, 'foo' ] ], /search string expected as <String> but was/)
223
- end
224
-
225
- def test_parse_deleted
226
- make_search_parser{
227
- add_msg('foo')
228
- add_msg('foo')
229
- assert_msg_uid(1, 2)
230
-
231
- set_msg_flag(1, 'deleted', true)
232
- assert_msg_flag('deleted', true, false)
233
- }
234
-
235
- parse_search_key([ 'DELETED' ]) {
236
- assert_search_cond(0, true)
237
- assert_search_cond(1, false)
238
- }
239
- end
240
-
241
- def test_parse_draft
242
- make_search_parser{
243
- add_msg('foo')
244
- add_msg('foo')
245
- assert_msg_uid(1, 2)
246
-
247
- set_msg_flag(1, 'draft', true)
248
- assert_msg_flag('draft', true, false)
249
- }
250
-
251
- parse_search_key([ 'DRAFT' ]) {
252
- assert_search_cond(0, true)
253
- assert_search_cond(1, false)
254
- }
255
- end
256
-
257
- def test_parse_flagged
258
- make_search_parser{
259
- add_msg('foo')
260
- add_msg('foo')
261
- assert_msg_uid(1, 2)
262
-
263
- set_msg_flag(1, 'flagged', true)
264
- assert_msg_flag('flagged', true, false)
265
- }
266
-
267
- parse_search_key([ 'FLAGGED' ]) {
268
- assert_search_cond(0, true)
269
- assert_search_cond(1, false)
270
- }
271
- end
272
-
273
- def test_parse_from
274
- make_search_parser{
275
- add_msg("From: foo\r\n" +
276
- "\r\n" +
277
- "foo")
278
- add_msg("From: bar\r\n" +
279
- "\r\n" +
280
- "foo")
281
- add_msg('foo')
282
- assert_msg_uid(1, 2, 3)
283
- }
284
-
285
- parse_search_key([ 'FROM', 'foo' ]) {
286
- assert_search_cond(0, true)
287
- assert_search_cond(1, false)
288
- assert_search_cond(2, false)
289
- }
290
-
291
- assert_search_syntax_error([ 'FROM' ], /need for a search string/)
292
- assert_search_syntax_error([ 'FROM', [ :group, 'foo' ] ], /search string expected as <String> but was/)
293
- end
294
-
295
- def test_parse_header
296
- make_search_parser{
297
- add_msg("X-Foo: alice\r\n" +
298
- "X-Bar: bob\r\n" +
299
- "\r\n" +
300
- "foo")
301
- add_msg("X-Foo: bob\r\n" +
302
- "X-Bar: alice\r\n" +
303
- "\r\n" +
304
- "foo")
305
- add_msg('foo')
306
- assert_msg_uid(1, 2, 3)
307
- }
308
-
309
- parse_search_key([ 'HEADER', 'x-foo', 'alice' ]) {
310
- assert_search_cond(0, true)
311
- assert_search_cond(1, false)
312
- assert_search_cond(2, false)
313
- }
314
-
315
- parse_search_key([ 'HEADER', 'x-foo', 'bob' ]) {
316
- assert_search_cond(0, false)
317
- assert_search_cond(1, true)
318
- assert_search_cond(2, false)
319
- }
320
-
321
- parse_search_key([ 'HEADER', 'x-bar', 'alice' ]) {
322
- assert_search_cond(0, false)
323
- assert_search_cond(1, true)
324
- assert_search_cond(2, false)
325
- }
326
-
327
- parse_search_key([ 'HEADER', 'x-bar', 'bob' ]) {
328
- assert_search_cond(0, true)
329
- assert_search_cond(1, false)
330
- assert_search_cond(2, false)
331
- }
332
-
333
- assert_search_syntax_error([ 'HEADER' ], /need for a search string/)
334
- assert_search_syntax_error([ 'HEADER', 'Received' ], /need for a search string/)
335
- assert_search_syntax_error([ 'HEADER', 'Received', [ :group, 'foo' ] ], /search string expected as <String> but was/)
336
- assert_search_syntax_error([ 'HEADER', [ :group, 'Received' ], 'foo' ], /search string expected as <String> but was/)
337
- end
338
-
339
- def test_parse_keyword
340
- make_search_parser{
341
- add_msg('')
342
- assert_msg_uid(1)
343
- }
344
-
345
- parse_search_key([ 'KEYWORD', 'foo' ]) {
346
- assert_search_cond(0, false) # always false
347
- }
348
-
349
- assert_search_syntax_error([ 'KEYWORD' ], /need for a search string/)
350
- assert_search_syntax_error([ 'KEYWORD', [ :group, 'foo' ] ], /search string expected as <String> but was/)
351
- end
352
-
353
- def test_parse_larger
354
- make_search_parser{
355
- add_msg('foo')
356
- add_msg('1234')
357
- add_msg('bar')
358
- assert_msg_uid(1, 2, 3)
359
- }
360
-
361
- parse_search_key([ 'LARGER', '3' ]) {
362
- assert_search_cond(0, false)
363
- assert_search_cond(1, true)
364
- assert_search_cond(2, false)
365
- }
366
-
367
- assert_search_syntax_error([ 'LARGER' ], /need for a octet size/)
368
- assert_search_syntax_error([ 'LARGER', [ :group, '3' ] ], /octet size is expected as numeric string but was/)
369
- assert_search_syntax_error([ 'LARGER', 'nonum' ], /octet size is expected as numeric string but was/)
370
- end
371
-
372
- def test_parse_new
373
- make_search_parser{
374
- add_msg('foo')
375
- add_msg('bar')
376
- add_msg('baz')
377
- assert_msg_uid(1, 2, 3)
378
-
379
- set_msg_flag(3, 'recent', false)
380
- set_msg_flag(2, 'seen', true)
381
- assert_msg_flag('recent', true, true, false)
382
- assert_msg_flag('seen', false, true, false)
383
- }
384
-
385
- parse_search_key([ 'NEW' ]) {
386
- assert_search_cond(0, true)
387
- assert_search_cond(1, false)
388
- assert_search_cond(2, false)
389
- }
390
- end
391
-
392
- def test_parse_not
393
- make_search_parser{
394
- add_msg('foo')
395
- add_msg('1234')
396
- add_msg('bar')
397
- assert_msg_uid(1, 2, 3)
398
-
399
- set_msg_flag(1, 'answered', true)
400
- assert_msg_flag('answered', true, false, false)
401
- }
402
-
403
- parse_search_key([ 'NOT', 'LARGER', '3' ]) {
404
- assert_search_cond(0, true)
405
- assert_search_cond(1, false)
406
- assert_search_cond(2, true)
407
- }
408
-
409
- parse_search_key([ 'NOT', 'ANSWERED' ]) {
410
- assert_search_cond(0, false)
411
- assert_search_cond(1, true)
412
- assert_search_cond(2, true)
413
- }
414
-
415
- assert_search_syntax_error([ 'NOT' ], 'unexpected end of search key.')
416
- end
417
-
418
- def test_parse_old
419
- make_search_parser{
420
- add_msg('foo')
421
- add_msg('bar')
422
- assert_msg_uid(1, 2)
423
-
424
- set_msg_flag(1, 'recent', false)
425
- assert_msg_flag('recent', false, true)
426
- }
427
-
428
- parse_search_key([ 'OLD' ]) {
429
- assert_search_cond(0, true)
430
- assert_search_cond(1, false)
431
- }
432
- end
433
-
434
- def test_parse_on
435
- make_search_parser{
436
- add_msg('foo', Time.parse('2013-11-07 12:34:56'))
437
- add_msg('foo', Time.parse('2013-11-08 12:34:56'))
438
- add_msg('foo', Time.parse('2013-11-09 12:34:56'))
439
- assert_msg_uid(1, 2, 3)
440
- }
441
-
442
- parse_search_key([ 'ON', '08-Nov-2013' ]) {
443
- assert_search_cond(0, false)
444
- assert_search_cond(1, true)
445
- assert_search_cond(2, false)
446
- }
447
-
448
- assert_search_syntax_error([ 'ON' ], /need for a search date/)
449
- assert_search_syntax_error([ 'ON', '99-Nov-2013' ], /search date is invalid/)
450
- assert_search_syntax_error([ 'ON', [ :group, '08-Nov-2013'] ], /search date string expected as <String> but was/)
451
- end
452
-
453
- def test_parse_or
454
- make_search_parser{
455
- add_msg('foo')
456
- add_msg('foo')
457
- add_msg('foo')
458
- add_msg('foo')
459
- assert_msg_uid(1, 2, 3, 4)
460
-
461
- set_msg_flag(1, 'answered', true)
462
- set_msg_flag(2, 'answered', true)
463
- set_msg_flag(1, 'flagged', true)
464
- set_msg_flag(3, 'flagged', true)
465
- assert_msg_flag('answered', true, true, false, false)
466
- assert_msg_flag('flagged', true, false, true, false)
467
- }
468
-
469
- parse_search_key([ 'OR', 'ANSWERED', 'FLAGGED' ]) {
470
- assert_search_cond(0, true)
471
- assert_search_cond(1, true)
472
- assert_search_cond(2, true)
473
- assert_search_cond(3, false)
474
-
475
- }
476
-
477
- assert_search_syntax_error([ 'OR' ], 'unexpected end of search key.')
478
- assert_search_syntax_error([ 'OR', 'ANSWERED' ], 'unexpected end of search key.')
479
- end
480
-
481
- def test_parse_recent
482
- make_search_parser{
483
- add_msg('foo')
484
- add_msg('foo')
485
- assert_msg_uid(1, 2)
486
-
487
- set_msg_flag(1, 'recent', false)
488
- assert_msg_flag('recent', false, true)
489
- }
490
-
491
- parse_search_key([ 'RECENT' ]) {
492
- assert_search_cond(0, false)
493
- assert_search_cond(1, true)
494
- }
495
- end
496
-
497
- def test_parse_seen
498
- make_search_parser{
499
- add_msg('foo')
500
- add_msg('foo')
501
- assert_msg_uid(1, 2)
502
-
503
- set_msg_flag(1, 'seen', true)
504
- assert_msg_flag('seen', true, false)
505
- }
506
-
507
- parse_search_key([ 'SEEN' ]) {
508
- assert_search_cond(0, true)
509
- assert_search_cond(1, false)
510
- }
511
- end
512
-
513
- def test_parse_sentbefore
514
- make_search_parser{
515
- add_msg("Date: Thu, 07 Nov 2013 12:34:56 +0900\r\n" +
516
- "\r\n" +
517
- "foo")
518
- add_msg("Date: Fri, 08 Nov 2013 12:34:56 +0900\r\n" +
519
- "\r\n" +
520
- "foo")
521
- add_msg("Date: Sat, 09 Nov 2013 12:34:56 +0900\r\n" +
522
- "\r\n" +
523
- "foo")
524
- add_msg('foo')
525
- assert_msg_uid(1, 2, 3, 4)
526
- }
527
-
528
- parse_search_key([ 'SENTBEFORE', '08-Nov-2013' ]) {
529
- assert_search_cond(0, true)
530
- assert_search_cond(1, false)
531
- assert_search_cond(2, false)
532
- assert_search_cond(3, false)
533
- }
534
-
535
- assert_search_syntax_error([ 'SENTBEFORE' ], /need for a search date/)
536
- assert_search_syntax_error([ 'SENTBEFORE', '99-Nov-2013' ], /search date is invalid/)
537
- assert_search_syntax_error([ 'SENTBEFORE', [ :group, '08-Nov-2013'] ], /search date string expected as <String> but was/)
538
- end
539
-
540
- def test_parse_senton
541
- make_search_parser{
542
- add_msg("Date: Thu, 07 Nov 2013 12:34:56 +0900\r\n" +
543
- "\r\n" +
544
- "foo")
545
- add_msg("Date: Fri, 08 Nov 2013 12:34:56 +0900\r\n" +
546
- "\r\n" +
547
- "foo")
548
- add_msg("Date: Sat, 09 Nov 2013 12:34:56 +0900\r\n" +
549
- "\r\n" +
550
- "foo")
551
- add_msg('foo')
552
- assert_msg_uid(1, 2, 3, 4)
553
- }
554
-
555
- parse_search_key([ 'SENTON', '08-Nov-2013' ]) {
556
- assert_search_cond(0, false)
557
- assert_search_cond(1, true)
558
- assert_search_cond(2, false)
559
- assert_search_cond(3, false)
560
- }
561
-
562
- assert_search_syntax_error([ 'SENTON' ], /need for a search date/)
563
- assert_search_syntax_error([ 'SENTON', '99-Nov-2013' ], /search date is invalid/)
564
- assert_search_syntax_error([ 'SENTON', [ :group, '08-Nov-2013'] ], /search date string expected as <String> but was/)
565
- end
566
-
567
- def test_parse_sentsince
568
- make_search_parser{
569
- add_msg("Date: Thu, 07 Nov 2013 12:34:56 +0900\r\n" +
570
- "\r\n" +
571
- "foo")
572
- add_msg("Date: Fri, 08 Nov 2013 12:34:56 +0900\r\n" +
573
- "\r\n" +
574
- "foo")
575
- add_msg("Date: Sat, 09 Nov 2013 12:34:56 +0900\r\n" +
576
- "\r\n" +
577
- "foo")
578
- add_msg('foo')
579
- assert_msg_uid(1, 2, 3, 4)
580
- }
581
-
582
- parse_search_key([ 'SENTSINCE', '08-Nov-2013' ]) {
583
- assert_search_cond(0, false)
584
- assert_search_cond(1, false)
585
- assert_search_cond(2, true)
586
- assert_search_cond(3, false)
587
- }
588
-
589
- assert_search_syntax_error([ 'SENTSINCE' ], /need for a search date/)
590
- assert_search_syntax_error([ 'SENTSINCE', '99-Nov-2013' ], /search date is invalid/)
591
- assert_search_syntax_error([ 'SENTSINCE', [ :group, '08-Nov-2013'] ], /search date string expected as <String> but was/)
592
- end
593
-
594
- def test_parse_since
595
- make_search_parser{
596
- add_msg('foo', Time.parse('2013-11-07 12:34:56'))
597
- add_msg('foo', Time.parse('2013-11-08 12:34:56'))
598
- add_msg('foo', Time.parse('2013-11-09 12:34:56'))
599
- assert_msg_uid(1, 2, 3)
600
- }
601
-
602
- parse_search_key([ 'SINCE', '08-Nov-2013' ]) {
603
- assert_search_cond(0, false)
604
- assert_search_cond(1, false)
605
- assert_search_cond(2, true)
606
- }
607
-
608
- assert_search_syntax_error([ 'SINCE' ], /need for a search date/)
609
- assert_search_syntax_error([ 'SINCE', '99-Nov-2013' ], /search date is invalid/)
610
- assert_search_syntax_error([ 'SINCE', [ :group, '08-Nov-2013'] ], /search date string expected as <String> but was/)
611
- end
612
-
613
- def test_parse_smaller
614
- make_search_parser{
615
- add_msg('foo')
616
- add_msg('12')
617
- add_msg('bar')
618
- assert_msg_uid(1, 2, 3)
619
- }
620
-
621
- parse_search_key([ 'SMALLER', '3' ]) {
622
- assert_search_cond(0, false)
623
- assert_search_cond(1, true)
624
- assert_search_cond(2, false)
625
- }
626
-
627
- assert_search_syntax_error([ 'SMALLER' ], /need for a octet size/)
628
- assert_search_syntax_error([ 'SMALLER', [ :group, '3' ] ], /octet size is expected as numeric string but was/)
629
- assert_search_syntax_error([ 'SMALLER', 'nonum' ], /octet size is expected as numeric string but was/)
630
- end
631
-
632
- def test_parse_subject
633
- make_search_parser{
634
- add_msg("Subject: foo\r\n" +
635
- "\r\n" +
636
- "foo")
637
- add_msg("Subject: bar\r\n" +
638
- "\r\n" +
639
- "foo")
640
- add_msg('foo')
641
- assert_msg_uid(1, 2, 3)
642
- }
643
-
644
- parse_search_key([ 'SUBJECT', 'foo' ]) {
645
- assert_search_cond(0, true)
646
- assert_search_cond(1, false)
647
- assert_search_cond(2, false)
648
- }
649
-
650
- assert_search_syntax_error([ 'SUBJECT' ], /need for a search string/)
651
- assert_search_syntax_error([ 'SUBJECT', [ :group, 'foo' ] ], /search string expected as <String> but was/)
652
- end
653
-
654
- def test_parse_text
655
- make_search_parser{
656
- add_msg("Content-Type: text/plain\r\n" +
657
- "Subject: foo\r\n" +
658
- "\r\n" +
659
- "bar")
660
- assert_msg_uid(1)
661
- }
662
-
663
- parse_search_key([ 'TEXT', 'jec' ]) {
664
- assert_search_cond(0, true)
665
- }
666
- parse_search_key([ 'TEXT', 'foo' ]) {
667
- assert_search_cond(0, true)
668
- }
669
- parse_search_key([ 'TEXT', 'bar' ]) {
670
- assert_search_cond(0, true)
671
- }
672
- parse_search_key([ 'TEXT', 'baz' ]) {
673
- assert_search_cond(0, false)
674
- }
675
-
676
- assert_search_syntax_error([ 'TEXT' ], /need for a search string/)
677
- assert_search_syntax_error([ 'TEXT', [ :group, 'foo'] ], /search string expected as <String> but was/)
678
- end
679
-
680
- def test_parse_text_multipart
681
- make_mail_multipart
682
- make_search_parser{
683
- add_msg(@mpart_mail.raw_source)
684
- assert_msg_uid(1)
685
- }
686
-
687
- parse_search_key([ 'TEXT', 'Subject: multipart test' ]) {
688
- assert_search_cond(0, true)
689
- }
690
- parse_search_key([ 'TEXT', 'Subject: inner multipart' ]) {
691
- assert_search_cond(0, true)
692
- }
693
- parse_search_key([ 'TEXT', 'Hello world.' ]) {
694
- assert_search_cond(0, true)
695
- }
696
- parse_search_key([ 'TEXT', 'HALO' ]) {
697
- assert_search_cond(0, true)
698
- }
699
- parse_search_key([ 'TEXT', 'detarame' ]) {
700
- assert_search_cond(0, false)
701
- }
702
- end
703
-
704
- def test_parse_to
705
- make_search_parser{
706
- add_msg("To: foo\r\n" +
707
- "\r\n" +
708
- "foo")
709
- add_msg("To: bar\r\n" +
710
- "\r\n" +
711
- "foo")
712
- add_msg('foo')
713
- assert_msg_uid(1, 2, 3)
714
- }
715
-
716
- parse_search_key([ 'TO', 'foo' ]) {
717
- assert_search_cond(0, true)
718
- assert_search_cond(1, false)
719
- assert_search_cond(2, false)
720
- }
721
-
722
- assert_search_syntax_error([ 'TO' ], /need for a search string/)
723
- assert_search_syntax_error([ 'TO', [ :group, 'foo' ] ], /search string expected as <String> but was/)
215
+ EOF
216
+ {}
217
+ ]
218
+ ]
219
+ })
220
+ [ [ 'us-ascii', %w[ CC foo ], [ true, true, false, false, false, false, false, false ] ],
221
+ [ 'charset', %W[ CC \u306F\u306B\u307B ], [ false, false, false, false, true, false, true, false ], 'utf-8' ]
222
+ ].each do |label, search, cond_list, charset|
223
+ data("CC:#{label}", {
224
+ search: search,
225
+ charset: charset,
226
+ messages: [
227
+ [ "Cc: foo\r\n" +
228
+ "\r\n" +
229
+ "foo",
230
+ {}
231
+ ],
232
+ [ "Cc: FOO\r\n" +
233
+ "\r\n" +
234
+ "foo",
235
+ {}
236
+ ],
237
+ [ "Cc: bar\r\n" +
238
+ "\r\n" +
239
+ "foo",
240
+ {}
241
+ ],
242
+ [ 'foo',
243
+ {}
244
+ ],
245
+ [ "Cc: =?UTF-8?B?44GE44KN44Gv44Gr44G744G444Go?=\r\n" +
246
+ "\r\n" +
247
+ "foo",
248
+ {},
249
+ ],
250
+ [ "Cc: =?UTF-8?B?44Gh44KK44Gs44KL44KS?=\r\n" +
251
+ "\r\n" +
252
+ "foo",
253
+ {}
254
+ ],
255
+ [ "Cc: =?ISO-2022-JP?B?GyRCJCQkbSRPJEskWyRYJEgbKEI=?=\r\n" +
256
+ "\r\n" +
257
+ "foo",
258
+ {},
259
+ ],
260
+ [ "Cc: =?ISO-2022-JP?B?GyRCJEEkaiRMJGskchsoQg==?=\r\n" +
261
+ "\r\n" +
262
+ "foo",
263
+ {},
264
+ ]
265
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
266
+ })
267
+ end
268
+ [ [ 'DELETED', %w[ DELETED ], [ true, false ] ],
269
+ [ 'UNDELETED', %w[ UNDELETED ], [ false, true ] ]
270
+ ].each do |label, search, cond_list|
271
+ data(label, {
272
+ search: search,
273
+ messages: [
274
+ [ 'foo', { deleted: true } ],
275
+ [ 'foo', { deleted: false } ]
276
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
277
+ })
278
+ end
279
+ [ [ 'DRAFT', %w[ DRAFT ], [ true, false ] ],
280
+ [ 'UNDRAFT', %w[ UNDRAFT ], [ false, true ] ]
281
+ ].each do |label, search, cond_list|
282
+ data(label, {
283
+ search: search,
284
+ messages: [
285
+ [ 'foo', { draft: true } ],
286
+ [ 'foo', { draft: false } ]
287
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
288
+ })
289
+ end
290
+ [ [ 'FLAGGED', %w[ FLAGGED ], [ true, false ] ],
291
+ [ 'UNFLAGGED', %w[ UNFLAGGED ], [ false, true ] ]
292
+ ].each do |label, search, cond_list|
293
+ data(label, {
294
+ search: search,
295
+ messages: [
296
+ [ 'foo', { flagged: true } ],
297
+ [ 'foo', { flagged: false } ]
298
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
299
+ })
300
+ end
301
+ [ [ 'us-ascii', %w[ FROM foo ], [ true, true, false, false, false, false, false, false ] ],
302
+ [ 'charset', %W[ FROM \u306F\u306B\u307B ],[ false, false, false, false, true, false, true, false ], 'utf-8' ]
303
+ ].each do |label, search, cond_list, charset|
304
+ data("FROM:#{label}", {
305
+ search: search,
306
+ charset: charset,
307
+ messages: [
308
+ [ "From: foo\r\n" +
309
+ "\r\n" +
310
+ "foo",
311
+ {}
312
+ ],
313
+ [ "From: FOO\r\n" +
314
+ "\r\n" +
315
+ "foo",
316
+ {}
317
+ ],
318
+ [ "From: bar\r\n" +
319
+ "\r\n" +
320
+ "foo",
321
+ {}
322
+ ],
323
+ [ 'foo',
324
+ {}
325
+ ],
326
+ [ "From: =?UTF-8?B?44GE44KN44Gv44Gr44G744G444Go?=\r\n" +
327
+ "\r\n" +
328
+ "foo",
329
+ {},
330
+ ],
331
+ [ "From: =?UTF-8?B?44Gh44KK44Gs44KL44KS?=\r\n" +
332
+ "\r\n" +
333
+ "foo",
334
+ {}
335
+ ],
336
+ [ "From: =?ISO-2022-JP?B?GyRCJCQkbSRPJEskWyRYJEgbKEI=?=\r\n" +
337
+ "\r\n" +
338
+ "foo",
339
+ {},
340
+ ],
341
+ [ "From: =?ISO-2022-JP?B?GyRCJEEkaiRMJGskchsoQg==?=\r\n" +
342
+ "\r\n" +
343
+ "foo",
344
+ {},
345
+ ]
346
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
347
+ })
348
+ end
349
+ [ [ 'x-foo_alice', %w[ HEADER x-foo alice ], [ true, true, false, false, false ] ],
350
+ [ 'x-foo_bob', %w[ HEADER x-foo bob ], [ false, false, true, true, false ] ],
351
+ [ 'x-foo_foo', %w[ HEADER x-foo foo ], [ false, false, false, false, false ] ],
352
+ [ 'x-bar_alice', %w[ HEADER x-bar alice ], [ false, false, true, true, false ] ],
353
+ [ 'x-bar_bob', %w[ HEADER x-bar bob ], [ true, true, false, false, false ] ],
354
+ [ 'x-bar_foo', %w[ HEADER x-bar foo ], [ false, false, false, false, false ] ]
355
+ ].each do |label, search, cond_list|
356
+ data("HEADER:#{label}", {
357
+ search: search,
358
+ messages: [
359
+ [ "X-Foo: alice\r\n" +
360
+ "X-Bar: bob\r\n" +
361
+ "\r\n" +
362
+ "foo",
363
+ {}
364
+ ],
365
+ [ "X-Foo: Alice\r\n" +
366
+ "X-Bar: Bob\r\n" +
367
+ "\r\n" +
368
+ "foo",
369
+ {}
370
+ ],
371
+ [ "X-Foo: bob\r\n" +
372
+ "X-Bar: alice\r\n" +
373
+ "\r\n" +
374
+ "foo",
375
+ {},
376
+ ],
377
+ [ "X-Foo: Bob\r\n" +
378
+ "X-Bar: Alice\r\n" +
379
+ "\r\n" +
380
+ "foo",
381
+ {},
382
+ ],
383
+ [ 'foo',
384
+ {}
385
+ ]
386
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
387
+ })
388
+ end
389
+ data('HEADER:charset', {
390
+ search: %W[ HEADER x-foo \u306F\u306B\u307B ],
391
+ charset: 'utf-8',
392
+ messages: [
393
+ [ true,
394
+ "X-Foo: =?UTF-8?B?44GE44KN44Gv44Gr44G744G444Go?=\r\n" +
395
+ "\r\n" +
396
+ "foo",
397
+ {}
398
+ ],
399
+ [ false,
400
+ "X-Foo: =?UTF-8?B?44Gh44KK44Gs44KL44KS?=\r\n" +
401
+ "\r\n" +
402
+ "foo",
403
+ {}
404
+ ],
405
+ [ true,
406
+ "X-Foo: =?ISO-2022-JP?B?GyRCJCQkbSRPJEskWyRYJEgbKEI=?=\r\n" +
407
+ "\r\n" +
408
+ "foo",
409
+ {},
410
+ ],
411
+ [ false,
412
+ "X-Foo: =?ISO-2022-JP?B?GyRCJEEkaiRMJGskchsoQg==?=\r\n" +
413
+ "\r\n" +
414
+ "foo",
415
+ {},
416
+ ]
417
+ ]
418
+ })
419
+ [ [ 'KEYWORD', %w[ KEYWORD foo ], [ false ] ], # always false
420
+ [ 'UNKEYWORD', %w[ UNKEYWORD foo ], [ true ] ] # always true
421
+ ].each do |label, search, cond_list|
422
+ data(label, {
423
+ search: search,
424
+ messages: [
425
+ [ '', {} ]
426
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
427
+ })
428
+ end
429
+ [ [ 'LARGER', %w[ LARGER 3 ], [ false, false, true, false ] ],
430
+ [ 'SMALLER', %w[ SMALLER 3 ], [ false, true, false, false ] ]
431
+ ].each do |label, search, cond_list|
432
+ data(label, {
433
+ search: search,
434
+ messages: [
435
+ [ 'foo', {} ],
436
+ [ '12', {} ],
437
+ [ '1234', {} ],
438
+ [ 'bar', {} ]
439
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
440
+ })
441
+ end
442
+ [ [ 'NEW', %w[ NEW ], [ true, false, false ] ],
443
+ [ 'OLD', %w[ OLD ], [ false, false, true ] ]
444
+ ].each do |label, search, cond_list|
445
+ data(label, {
446
+ search: search,
447
+ messages: [
448
+ [ 'foo', { recent: true, seen: false } ],
449
+ [ 'bar', { recent: true, seen: true } ],
450
+ [ 'baz', { recent: false, seen: false } ]
451
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
452
+ })
453
+ end
454
+ [ [ 'LARGER', %w[ NOT LARGER 3 ], [ true, false, true ] ],
455
+ [ 'ANSWERED', %w[ NOT ANSWERED ], [ false, true, true ] ]
456
+ ].each do |label, search, cond_list|
457
+ data("NOT:#{label}", {
458
+ search: search,
459
+ messages: [
460
+ [ 'foo', { answered: true } ],
461
+ [ '1234', { answered: false } ],
462
+ [ 'bar', { answered: false } ]
463
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
464
+ })
465
+ end
466
+ data('OR', {
467
+ search: %w[ OR ANSWERED FLAGGED ],
468
+ messages: [
469
+ [ true, 'foo', { answered: true, flagged: true } ],
470
+ [ true, 'foo', { answered: true, flagged: false } ],
471
+ [ true, 'foo', { answered: false, flagged: true } ],
472
+ [ false, 'foo', { answered: false, flagged: false } ]
473
+ ]
474
+ })
475
+ data('RECENT', {
476
+ search: %w[ RECENT ],
477
+ messages: [
478
+ [ false, 'foo', { recent: false } ],
479
+ [ true, 'foo', { recent: true } ]
480
+ ]
481
+ })
482
+ [ [ 'SEEN', %w[ SEEN ], [ true, false ] ],
483
+ [ 'UNSEEN', %w[ UNSEEN ], [ false, true ] ]
484
+ ].each do |label, search, cond_list|
485
+ data(label, {
486
+ search: search,
487
+ messages: [
488
+ [ 'foo', { seen: true } ],
489
+ [ 'foo', { seen: false } ]
490
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
491
+ })
492
+ end
493
+ [ [ 'SENTBEFORE', %w[ SENTBEFORE 08-Nov-2013 ], [ true, false, false, false ] ],
494
+ [ 'SENTON', %w[ SENTON 08-Nov-2013 ], [ false, true, false, false ] ],
495
+ [ 'SENTSINCE', %w[ SENTSINCE 08-Nov-2013 ], [ false, false, true, false ] ],
496
+ ].each do |label, search, cond_list|
497
+ data(label, {
498
+ search: search,
499
+ messages: [
500
+ [ "Date: Thu, 07 Nov 2013 12:34:56 +0000\r\n" +
501
+ "\r\n" +
502
+ "foo",
503
+ {}
504
+ ],
505
+ [ "Date: Fri, 08 Nov 2013 12:34:56 +0000\r\n" +
506
+ "\r\n" +
507
+ "foo",
508
+ {}
509
+ ],
510
+ [ "Date: Sat, 09 Nov 2013 12:34:56 +0000\r\n" +
511
+ "\r\n" +
512
+ "foo",
513
+ {}
514
+ ],
515
+ [ 'foo',
516
+ {}
517
+ ]
518
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
519
+ })
520
+ end
521
+ [ [ 'us-ascii', %w[ SUBJECT foo ], [ true, true, false, false, false, false, false, false ] ],
522
+ [ 'charset', %W[ SUBJECT \u306F\u306B\u307B ], [ false, false, false, false, true, false, true, false ], 'utf-8' ]
523
+ ].each do |label, search, cond_list, charset|
524
+ data("SUBJECT:#{label}", {
525
+ search: search,
526
+ charset: charset,
527
+ messages: [
528
+ [ "Subject: foo\r\n" +
529
+ "\r\n" +
530
+ "foo",
531
+ {}
532
+ ],
533
+ [ "Subject: FOO\r\n" +
534
+ "\r\n" +
535
+ "foo",
536
+ {}
537
+ ],
538
+ [ "Subject: bar\r\n" +
539
+ "\r\n" +
540
+ "foo",
541
+ {}
542
+ ],
543
+ [ 'foo',
544
+ {}
545
+ ],
546
+ [ "Subject: =?UTF-8?B?44GE44KN44Gv44Gr44G744G444Go?=\r\n" +
547
+ "\r\n" +
548
+ "foo",
549
+ {},
550
+ ],
551
+ [ "Subject: =?UTF-8?B?44Gh44KK44Gs44KL44KS?=\r\n" +
552
+ "\r\n" +
553
+ "foo",
554
+ {}
555
+ ],
556
+ [ "Subject: =?ISO-2022-JP?B?GyRCJCQkbSRPJEskWyRYJEgbKEI=?=\r\n" +
557
+ "\r\n" +
558
+ "foo",
559
+ {},
560
+ ],
561
+ [ "Subject: =?ISO-2022-JP?B?GyRCJEEkaiRMJGskchsoQg==?=\r\n" +
562
+ "\r\n" +
563
+ "foo",
564
+ {},
565
+ ]
566
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
567
+ })
568
+ end
569
+ [ [ 'header_field_name', %w[ TEXT jec ], [ true ] ],
570
+ [ 'case_insensitive', %w[ TEXT sUB ], [ true ] ],
571
+ [ 'header_field_value', %w[ TEXT foo ], [ true ] ],
572
+ [ 'body', %w[ TEXT bar ], [ true ] ],
573
+ [ 'no_match', %w[ TEXT baz ], [ false ] ]
574
+ ].each do |label, search, cond_list|
575
+ data("TEXT:#{label}", {
576
+ search: search,
577
+ messages: [
578
+ [ "Content-Type: text/plain\r\n" +
579
+ "Subject: foo\r\n" +
580
+ "\r\n" +
581
+ "bar",
582
+ {}
583
+ ]
584
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
585
+ })
586
+ end
587
+ [ [ 'header', [ 'TEXT', 'Subject: multipart test' ], [ true ] ],
588
+ [ 'inner_header', [ 'TEXT', 'Subject: inner multipart' ], [ true ] ],
589
+ [ 'part_body', [ 'TEXT', 'Hello world.' ], [ true ] ],
590
+ [ 'inner_part_body', [ 'TEXT', 'HALO' ], [ true ] ],
591
+ [ 'no_match', [ 'TEXT', 'detarame' ], [ false ] ]
592
+ ].each do |label, search, cond_list|
593
+ data("TEXT:multipart:#{label}", {
594
+ search: search,
595
+ messages: [
596
+ [ MPART_MAIL_TEXT, {} ]
597
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
598
+ })
599
+ end
600
+ [ [ 'us-ascii', %w[ TO foo ], [ true, true, false, false, false, false, false, false ] ],
601
+ [ 'charset', %W[ TO \u306F\u306B\u307B ], [ false, false, false, false, true, false, true, false ], 'utf-8' ]
602
+ ].each do |label, search, cond_list, charset|
603
+ data("TO:#{label}", {
604
+ search: search,
605
+ charset: charset,
606
+ messages: [
607
+ [ "To: foo\r\n" +
608
+ "\r\n" +
609
+ "foo",
610
+ {}
611
+ ],
612
+ [ "To: FOO\r\n" +
613
+ "\r\n" +
614
+ "foo",
615
+ {}
616
+ ],
617
+ [ "To: bar\r\n" +
618
+ "\r\n" +
619
+ "foo",
620
+ {}
621
+ ],
622
+ [ 'foo',
623
+ {}
624
+ ],
625
+ [ "To: =?UTF-8?B?44GE44KN44Gv44Gr44G744G444Go?=\r\n" +
626
+ "\r\n" +
627
+ "foo",
628
+ {},
629
+ ],
630
+ [ "To: =?UTF-8?B?44Gh44KK44Gs44KL44KS?=\r\n" +
631
+ "\r\n" +
632
+ "foo",
633
+ {}
634
+ ],
635
+ [ "To: =?ISO-2022-JP?B?GyRCJCQkbSRPJEskWyRYJEgbKEI=?=\r\n" +
636
+ "\r\n" +
637
+ "foo",
638
+ {},
639
+ ],
640
+ [ "To: =?ISO-2022-JP?B?GyRCJEEkaiRMJGskchsoQg==?=\r\n" +
641
+ "\r\n" +
642
+ "foo",
643
+ {},
644
+ ]
645
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
646
+ })
647
+ end
648
+ [ [ 'us-ascii', %w[ BODY foo ], [ true, true, true, false, false ] ],
649
+ [ 'us-ascii:no_match', %w[ BODY bar ], [ false, false, false, false, false ] ],
650
+ [ 'utf-8', %W[ BODY \u306F\u306B\u307B ], [ false, false, false, true, true ] ]
651
+ ].each do |label, search, cond_list|
652
+ data("BODY:charset:#{label}", {
653
+ search: search,
654
+ charset: 'utf-8',
655
+ messages: [
656
+ [ "Content-Type: text/plain\r\n" +
657
+ "\r\n" +
658
+ "foo",
659
+ {}
660
+ ],
661
+ [ "Content-Type: text/plain; charset=utf-8\r\n" +
662
+ "\r\n" +
663
+ "foo",
664
+ {}
665
+ ],
666
+ [ "Content-Type: text/plain; charset=iso-2022-jp\r\n" +
667
+ "\r\n" +
668
+ "foo",
669
+ {}
670
+ ],
671
+ [ "Content-Type: text/plain; charset=utf-8\r\n" +
672
+ "\r\n" +
673
+ "\u3053\u3093\u306B\u3061\u306F\r\n" +
674
+ "\u3044\u308D\u306F\u306B\u307B\u3078\u3068\r\n" +
675
+ "\u3042\u3044\u3046\u3048\u304A\r\n",
676
+ {}
677
+ ],
678
+ [ "Content-Type: text/plain; charset=iso-2022-jp\r\n" +
679
+ "\r\n" +
680
+ "\e$B$3$s$K$A$O\e(B\r\n\e$B$$$m$O$K$[$X$H\e(B\r\n\e$B$\"$$$&$($*\e(B\r\n",
681
+ {}
682
+ ]
683
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
684
+ })
685
+ end
686
+ [ [ 'us-ascii:header_and_body', %w[ TEXT foo ], [ true, true, true, false, false, false, false ] ],
687
+ [ 'us-ascii:body', %w[ TEXT bar ], [ false, true, true, false, false, false, false ] ],
688
+ [ 'us-ascii:no_match', %w[ TEXT baz ], [ false, false, false, false, false, false, false ] ],
689
+ [ 'utf-8:header_and_body', %W[ TEXT \u306F\u306B\u307B ], [ false, false, false, true, true, true, true ] ]
690
+ ].each do |label, search, cond_list|
691
+ data("TEXT:charset:#{label}", {
692
+ search: search,
693
+ charset: 'utf-8',
694
+ messages: [
695
+ [ "Content-Type: text/plain\r\n" +
696
+ "\r\n" +
697
+ "foo",
698
+ {}
699
+ ],
700
+ [ "Content-Type: text/plain; charset=utf-8\r\n" +
701
+ "X-foo: dummy\r\n" +
702
+ "\r\n" +
703
+ "bar",
704
+ {}
705
+ ],
706
+ [ "Content-Type: text/plain; charset=iso-2022-jp\r\n" +
707
+ "X-dummy: foo\r\n" +
708
+ "\r\n" +
709
+ "bar",
710
+ {}
711
+ ],
712
+ [ "Content-Type: text/plain; charset=utf-8\r\n" +
713
+ "\r\n" +
714
+ "\u3053\u3093\u306B\u3061\u306F\r\n" +
715
+ "\u3044\u308D\u306F\u306B\u307B\u3078\u3068\r\n" +
716
+ "\u3042\u3044\u3046\u3048\u304A\r\n",
717
+ {}
718
+ ],
719
+ [ "Content-Type: text/plain; charset=iso-2022-jp\r\n" +
720
+ "\r\n" +
721
+ "\e$B$3$s$K$A$O\e(B\r\n\e$B$$$m$O$K$[$X$H\e(B\r\n\e$B$\"$$$&$($*\e(B\r\n",
722
+ {}
723
+ ],
724
+ [ "Subject: =?UTF-8?B?44GE44KN44Gv44Gr44G744G444Go?=\r\n" +
725
+ "\r\n" +
726
+ "",
727
+ {}
728
+ ],
729
+ [ "Subject: =?ISO-2022-JP?B?GyRCJCQkbSRPJEskWyRYJEgbKEI=?=\r\n" +
730
+ "\r\n" +
731
+ "",
732
+ {},
733
+ ]
734
+ ].zip(cond_list).map{|msg, cond| [ cond] + msg }
735
+ })
736
+ end
737
+ data('msg_set', {
738
+ search: %w[ 1,2,* ],
739
+ messages: [
740
+ [ true, 'foo', {} ],
741
+ [ true, 'foo', {} ],
742
+ [ false, 'foo', {} ],
743
+ [ false, 'foo', {} ],
744
+ [ true, 'foo', {} ]
745
+ ]
746
+ })
747
+ [ [ 'list', %w[ ANSWERED FLAGGED ], [ true, false, false, false ] ],
748
+ [ 'group', [ [ :group, 'ANSWERED', 'FLAGGED' ] ], [ true, false, false, false ] ]
749
+ ].each do |label, search, cond_list|
750
+ data("group:#{label}", {
751
+ search: search,
752
+ messages: [
753
+ [ 'foo', { answered: true, flagged: true } ],
754
+ [ 'foo', { answered: true, flagged: false } ],
755
+ [ 'foo', { answered: false, flagged: true } ],
756
+ [ 'foo', { answered: false, flagged: false } ]
757
+ ].zip(cond_list).map{|msg, cond| [ cond ] + msg }
758
+ })
759
+ end
760
+ def test_parse_and_search(data)
761
+ search = data[:search]
762
+ charset = data[:charset]
763
+ msg_list = data[:messages]
764
+
765
+ make_search_parser(charset: charset) {
766
+ for _, msg, flags, *optional in msg_list
767
+ uid = add_msg(msg, *optional)
768
+ for name, value in flags
769
+ set_msg_flag(uid, name.to_s, value)
770
+ end
771
+ end
772
+ }
773
+
774
+ search = search.map{|key| (key.is_a? String) ? key.b : key }
775
+ parse_search_key(search) {
776
+ msg_list.each_with_index do |(expected_cond, *_), i|
777
+ assert_search_cond(i, expected_cond, "message index: #{i}")
778
+ end
779
+ }
780
+ end
781
+
782
+ %w[ BCC BODY CC FROM KEYWORD SUBJECT TEXT TO UNKEYWORD ].each do |key|
783
+ data("#{key}:no_string", [
784
+ [ key ],
785
+ /need for a search string/
786
+ ])
787
+ data("#{key}:not_string", [
788
+ [ key, [ :group, 'foo' ] ],
789
+ /search string expected as <String> but was/
790
+ ])
791
+ end
792
+ %w[ BEFORE ON SENTBEFORE SENTON SENTSINCE SINCE ].each do |key|
793
+ data("#{key}:no_date", [
794
+ [ key ],
795
+ /need for a search date/
796
+ ])
797
+ data("#{key}:invalid_date", [
798
+ [ key, '99-Nov-2013' ],
799
+ /search date is invalid/
800
+ ])
801
+ data("#{key}:not_date", [
802
+ [ key, [ :group, '08-Nov-2013'] ],
803
+ /search date string expected as <String> but was/
804
+ ])
805
+ end
806
+ %w[ LARGER SMALLER ].each do |key|
807
+ data("#{key}:no_size", [
808
+ %w[ LARGER ],
809
+ /need for a octet size/
810
+ ])
811
+ data("#{key}:invalid_size", [
812
+ %w[ LARGER nonum ],
813
+ /octet size is expected as numeric string but was/
814
+ ])
815
+ data("#{key}:not_size", [
816
+ [ 'LARGER', [ :group, '3' ] ],
817
+ /octet size is expected as numeric string but was/
818
+ ])
819
+ end
820
+ data('HEADER:no_field_name', [
821
+ %w[ HEADER ],
822
+ /need for a search string/
823
+ ])
824
+ data('HEADER:no_string', [
825
+ %w[ HEADER Received ],
826
+ /need for a search string/
827
+ ])
828
+ data('HEADER:not_field_name', [
829
+ [ 'HEADER', [ :group, 'Received' ], 'foo' ],
830
+ /search string expected as <String> but was/
831
+ ])
832
+ data('HEADER:not_string', [
833
+ [ 'HEADER', 'Received', [ :group, 'foo' ] ],
834
+ /search string expected as <String> but was/
835
+ ])
836
+ data('NOT:no_search_key', [
837
+ %w[ NOT ],
838
+ 'unexpected end of search key.'
839
+ ])
840
+ data('OR:no_left_search_key', [
841
+ %w[ OR ],
842
+ 'unexpected end of search key.'
843
+ ])
844
+ data('OR:no_right_search_key', [
845
+ %w[ OR ANSWERED ],
846
+ 'unexpected end of search key.'
847
+ ])
848
+ [ [ 'string', %w[ detarame ] ],
849
+ [ 'symbol', [ :detarame ] ],
850
+ [ 'array', [ [ :detarame, 'ANSWERED', 'FLAGGED' ] ] ],
851
+ ].each do |label, search_key|
852
+ data("unknown_search_key:#{label}", [
853
+ search_key,
854
+ /unknown search key/
855
+ ])
856
+ end
857
+ def test_search_syntax_error(data)
858
+ search, expected_pattern = data
859
+ make_search_parser
860
+ assert_search_syntax_error(search, expected_pattern)
724
861
  end
725
862
 
726
863
  def test_parse_uid
@@ -741,269 +878,10 @@ Content-Type: text/html
741
878
  assert_search_cond(2, true)
742
879
  }
743
880
 
744
- begin
745
- @parser.parse([ 'UID', 'detarame' ])
746
- rescue
747
- error = $!
748
- end
881
+ error = assert_raise(RIMS::MessageSetSyntaxError) { @parser.parse([ 'UID', 'detarame' ]) }
749
882
  assert_kind_of(RIMS::SyntaxError, error)
750
- end
751
-
752
- def test_parse_unanswered
753
- make_search_parser{
754
- add_msg('foo')
755
- add_msg('foo')
756
- assert_msg_uid(1, 2)
757
-
758
- set_msg_flag(1, 'answered', true)
759
- assert_msg_flag('answered', true, false)
760
- }
761
-
762
- parse_search_key([ 'UNANSWERED' ]) {
763
- assert_search_cond(0, false)
764
- assert_search_cond(1, true)
765
- }
766
- end
767
-
768
- def test_parse_undeleted
769
- make_search_parser{
770
- add_msg('foo')
771
- add_msg('foo')
772
- assert_msg_uid(1, 2)
773
-
774
- set_msg_flag(1, 'deleted', true)
775
- assert_msg_flag('deleted', true, false)
776
- }
777
-
778
- parse_search_key([ 'UNDELETED' ]) {
779
- assert_search_cond(0, false)
780
- assert_search_cond(1, true)
781
- }
782
- end
783
-
784
- def test_parse_undraft
785
- make_search_parser{
786
- add_msg('foo')
787
- add_msg('foo')
788
- assert_msg_uid(1, 2)
789
-
790
- set_msg_flag(1, 'draft', true)
791
- assert_msg_flag('draft', true, false)
792
- }
793
-
794
- parse_search_key([ 'UNDRAFT' ]) {
795
- assert_search_cond(0, false)
796
- assert_search_cond(1, true)
797
- }
798
- end
799
-
800
- def test_parse_unflagged
801
- make_search_parser{
802
- add_msg('foo')
803
- add_msg('foo')
804
- assert_msg_uid(1, 2)
805
-
806
- set_msg_flag(1, 'flagged', true)
807
- assert_msg_flag('flagged', true, false)
808
- }
809
-
810
- parse_search_key([ 'UNFLAGGED' ]) {
811
- assert_search_cond(0, false)
812
- assert_search_cond(1, true)
813
- }
814
- end
815
-
816
- def test_parse_unkeyword
817
- make_search_parser{
818
- add_msg('')
819
- assert_msg_uid(1)
820
- }
821
-
822
- parse_search_key([ 'UNKEYWORD', 'foo' ]) {
823
- assert_search_cond(0, true) # always true
824
- }
825
-
826
- assert_search_syntax_error([ 'UNKEYWORD' ], /need for a search string/)
827
- assert_search_syntax_error([ 'UNKEYWORD', [ :group, 'foo' ] ], /search string expected as <String> but was/)
828
- end
829
-
830
- def test_parse_unseen
831
- make_search_parser{
832
- add_msg('foo')
833
- add_msg('foo')
834
- assert_msg_uid(1, 2)
835
-
836
- set_msg_flag(1, 'seen', true)
837
- assert_msg_flag('seen', true, false)
838
- }
839
-
840
- parse_search_key([ 'UNSEEN' ]) {
841
- assert_search_cond(0, false)
842
- assert_search_cond(1, true)
843
- }
844
- end
845
-
846
- def test_parse_msg_set
847
- make_search_parser{
848
- add_msg('foo')
849
- add_msg('foo')
850
- add_msg('foo')
851
- add_msg('foo')
852
- add_msg('foo')
853
- add_msg('foo')
854
- expunge(1, 3, 5)
855
- assert_msg_uid(2, 4, 6)
856
- }
857
-
858
- parse_search_key([ '1,*' ]) {
859
- assert_search_cond(0, true)
860
- assert_search_cond(1, false)
861
- assert_search_cond(2, true)
862
- }
863
-
864
- assert_search_syntax_error([ 'detarame' ], /unknown search key/)
865
- end
866
-
867
- def test_parse_group
868
- make_search_parser{
869
- add_msg('foo')
870
- add_msg('foo')
871
- add_msg('foo')
872
- add_msg('foo')
873
- assert_msg_uid(1, 2, 3, 4)
874
-
875
- set_msg_flag(1, 'answered', true)
876
- set_msg_flag(2, 'answered', true)
877
- set_msg_flag(1, 'flagged', true)
878
- set_msg_flag(3, 'flagged', true)
879
- assert_msg_flag('answered', true, true, false, false)
880
- assert_msg_flag('flagged', true, false, true, false)
881
- }
882
-
883
- parse_search_key([ 'ANSWERED', 'FLAGGED' ]) {
884
- assert_search_cond(0, true)
885
- assert_search_cond(1, false)
886
- assert_search_cond(2, false)
887
- assert_search_cond(3, false)
888
- }
889
-
890
- parse_search_key([ [ :group, 'ANSWERED', 'FLAGGED' ] ]) {
891
- assert_search_cond(0, true)
892
- assert_search_cond(1, false)
893
- assert_search_cond(2, false)
894
- assert_search_cond(3, false)
895
- }
896
-
897
- assert_search_syntax_error([ [ :block, 'ANSWERED', 'FLAGGED' ] ], /unknown search key/)
898
- end
899
-
900
- def test_parse_unknown
901
- make_search_parser{}
902
- assert_search_syntax_error([ :detarame ], /unknown search key/)
903
- end
904
-
905
- def test_parse_charset_body
906
- make_search_parser(charset: 'utf-8') {
907
- add_msg("Content-Type: text/plain\r\n" +
908
- "\r\n" +
909
- "foo")
910
- add_msg("Content-Type: text/plain; charset=utf-8\r\n" +
911
- "\r\n" +
912
- "foo")
913
- add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
914
- "\r\n" +
915
- "foo")
916
- add_msg("Content-Type: text/plain; charset=utf-8\r\n" +
917
- "\r\n" +
918
- "\u3053\u3093\u306B\u3061\u306F\r\n" +
919
- "\u3044\u308D\u306F\u306B\u307B\u3078\u3068\r\n" +
920
- "\u3042\u3044\u3046\u3048\u304A\r\n")
921
- add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
922
- "\r\n" +
923
- "\e$B$3$s$K$A$O\e(B\r\n\e$B$$$m$O$K$[$X$H\e(B\r\n\e$B$\"$$$&$($*\e(B\r\n")
924
- assert_msg_uid(1, 2, 3, 4, 5)
925
- }
926
-
927
- parse_search_key([ 'BODY', 'foo' ]) {
928
- assert_search_cond(0, true)
929
- assert_search_cond(1, true)
930
- assert_search_cond(2, true)
931
- assert_search_cond(3, false)
932
- assert_search_cond(4, false)
933
- }
934
-
935
- parse_search_key([ 'BODY', 'bar' ]) {
936
- assert_search_cond(0, false)
937
- assert_search_cond(1, false)
938
- assert_search_cond(2, false)
939
- assert_search_cond(3, false)
940
- assert_search_cond(4, false)
941
- }
942
-
943
- parse_search_key([ 'BODY', "\u306F\u306B\u307B".b ]) {
944
- assert_search_cond(0, false)
945
- assert_search_cond(1, false)
946
- assert_search_cond(2, false)
947
- assert_search_cond(3, true)
948
- assert_search_cond(4, true)
949
- }
950
- end
951
-
952
- def test_parse_charset_text
953
- make_search_parser(charset: 'utf-8') {
954
- add_msg("Content-Type: text/plain\r\n" +
955
- "\r\n" +
956
- "foo")
957
- add_msg("Content-Type: text/plain; charset=utf-8\r\n" +
958
- "X-foo: dummy\r\n" +
959
- "\r\n" +
960
- "bar")
961
- add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
962
- "X-dummy: foo\r\n" +
963
- "\r\n" +
964
- "bar")
965
- add_msg("Content-Type: text/plain; charset=utf-8\r\n" +
966
- "\r\n" +
967
- "\u3053\u3093\u306B\u3061\u306F\r\n" +
968
- "\u3044\u308D\u306F\u306B\u307B\u3078\u3068\r\n" +
969
- "\u3042\u3044\u3046\u3048\u304A\r\n")
970
- add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
971
- "\r\n" +
972
- "\e$B$3$s$K$A$O\e(B\r\n\e$B$$$m$O$K$[$X$H\e(B\r\n\e$B$\"$$$&$($*\e(B\r\n")
973
- assert_msg_uid(1, 2, 3, 4, 5)
974
- }
975
-
976
- parse_search_key([ 'TEXT', 'foo' ]) {
977
- assert_search_cond(0, true)
978
- assert_search_cond(1, true)
979
- assert_search_cond(2, true)
980
- assert_search_cond(3, false)
981
- assert_search_cond(4, false)
982
- }
983
-
984
- parse_search_key([ 'TEXT', 'bar' ]) {
985
- assert_search_cond(0, false)
986
- assert_search_cond(1, true)
987
- assert_search_cond(2, true)
988
- assert_search_cond(3, false)
989
- assert_search_cond(4, false)
990
- }
991
-
992
- parse_search_key([ 'TEXT', 'baz' ]) {
993
- assert_search_cond(0, false)
994
- assert_search_cond(1, false)
995
- assert_search_cond(2, false)
996
- assert_search_cond(3, false)
997
- assert_search_cond(4, false)
998
- }
999
-
1000
- parse_search_key([ 'TEXT', "\u306F\u306B\u307B".b ]) {
1001
- assert_search_cond(0, false)
1002
- assert_search_cond(1, false)
1003
- assert_search_cond(2, false)
1004
- assert_search_cond(3, true)
1005
- assert_search_cond(4, true)
1006
- }
883
+ assert_match(/invalid message sequence format/, error.message)
884
+ assert_match(/detarame/, error.message)
1007
885
  end
1008
886
  end
1009
887
  end