rims 0.2.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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/ChangeLog +379 -0
  4. data/Gemfile +11 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +566 -0
  7. data/Rakefile +29 -0
  8. data/bin/rims +11 -0
  9. data/lib/rims.rb +45 -0
  10. data/lib/rims/auth.rb +133 -0
  11. data/lib/rims/cksum_kvs.rb +68 -0
  12. data/lib/rims/cmd.rb +809 -0
  13. data/lib/rims/daemon.rb +338 -0
  14. data/lib/rims/db.rb +793 -0
  15. data/lib/rims/error.rb +23 -0
  16. data/lib/rims/gdbm_kvs.rb +76 -0
  17. data/lib/rims/hash_kvs.rb +66 -0
  18. data/lib/rims/kvs.rb +101 -0
  19. data/lib/rims/lock.rb +151 -0
  20. data/lib/rims/mail_store.rb +663 -0
  21. data/lib/rims/passwd.rb +251 -0
  22. data/lib/rims/pool.rb +88 -0
  23. data/lib/rims/protocol.rb +71 -0
  24. data/lib/rims/protocol/decoder.rb +1469 -0
  25. data/lib/rims/protocol/parser.rb +1114 -0
  26. data/lib/rims/rfc822.rb +456 -0
  27. data/lib/rims/server.rb +567 -0
  28. data/lib/rims/test.rb +391 -0
  29. data/lib/rims/version.rb +11 -0
  30. data/load_test/Rakefile +93 -0
  31. data/rims.gemspec +38 -0
  32. data/test/test_auth.rb +174 -0
  33. data/test/test_cksum_kvs.rb +121 -0
  34. data/test/test_config.rb +533 -0
  35. data/test/test_daemon_status_file.rb +169 -0
  36. data/test/test_daemon_waitpid.rb +72 -0
  37. data/test/test_db.rb +602 -0
  38. data/test/test_db_recovery.rb +732 -0
  39. data/test/test_error.rb +97 -0
  40. data/test/test_gdbm_kvs.rb +32 -0
  41. data/test/test_hash_kvs.rb +116 -0
  42. data/test/test_lock.rb +161 -0
  43. data/test/test_mail_store.rb +750 -0
  44. data/test/test_passwd.rb +203 -0
  45. data/test/test_protocol.rb +91 -0
  46. data/test/test_protocol_auth.rb +121 -0
  47. data/test/test_protocol_decoder.rb +6490 -0
  48. data/test/test_protocol_fetch.rb +994 -0
  49. data/test/test_protocol_request.rb +332 -0
  50. data/test/test_protocol_search.rb +974 -0
  51. data/test/test_rfc822.rb +696 -0
  52. metadata +174 -0
@@ -0,0 +1,332 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'logger'
4
+ require 'rims'
5
+ require 'test/unit'
6
+
7
+ module RIMS::Test
8
+ class ProtocolRequestReaderTest < Test::Unit::TestCase
9
+ def setup
10
+ @input = StringIO.new('', 'r')
11
+ @output = StringIO.new('', 'w')
12
+ @logger = Logger.new(STDOUT)
13
+ @logger.level = ($DEBUG) ? Logger::DEBUG : Logger::FATAL
14
+ @reader = RIMS::Protocol::RequestReader.new(@input, @output, @logger)
15
+ end
16
+
17
+ def test_scan_line
18
+ assert_equal([], @reader.scan_line(''))
19
+ assert_equal(%w[ abcd CAPABILITY ], @reader.scan_line('abcd CAPABILITY'))
20
+ assert_equal(%w[ abcd OK CAPABILITY completed ], @reader.scan_line('abcd OK CAPABILITY completed'))
21
+ assert_equal(%w[ * CAPABILITY IMAP4rev1 AUTH=KERBEROS_V4 ], @reader.scan_line('* CAPABILITY IMAP4rev1 AUTH=KERBEROS_V4'))
22
+ assert_equal(%w[ * 172 EXISTS ], @reader.scan_line('* 172 EXISTS'))
23
+ assert_equal([ '*', 'OK', '['.intern, 'UNSEEN', '12', ']'.intern, 'Message', '12', 'is', 'first', 'unseen' ],
24
+ @reader.scan_line('* OK [UNSEEN 12] Message 12 is first unseen'))
25
+ assert_equal([ '*', 'FLAGS', '('.intern, '\Answered', '\Flagged', '\Deleted', '\Seen', '\Draft', ')'.intern ],
26
+ @reader.scan_line('* FLAGS (\Answered \Flagged \Deleted \Seen \Draft)'))
27
+ assert_equal([ '*', 'OK', '['.intern, 'PERMANENTFLAGS', '('.intern, '\Deleted', '\Seen', '\*', ')'.intern, ']'.intern, 'Limited' ],
28
+ @reader.scan_line('* OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited'))
29
+ assert_equal([ 'A82', 'LIST', '', '*' ], @reader.scan_line('A82 LIST "" *'))
30
+ assert_equal([ '*', 'LIST', '('.intern, '\Noselect', ')'.intern, '/', 'foo' ], @reader.scan_line('* LIST (\Noselect) "/" foo',))
31
+ assert_equal([ '*', 'LIST', '('.intern, '\Noselect', ')'.intern, '/', 'foo [bar] (baz)' ],
32
+ @reader.scan_line('* LIST (\Noselect) "/" "foo [bar] (baz)"'))
33
+ assert_equal([ '*', 'LIST', '('.intern, '\Noselect', ')'.intern, :NIL, '' ], @reader.scan_line('* LIST (\Noselect) NIL ""'))
34
+ assert_equal([ 'A654', 'FETCH', '2:4',
35
+ '('.intern,
36
+ [ :body, RIMS::Protocol.body(symbol: 'BODY', section: '') ],
37
+ ')'.intern
38
+ ],
39
+ @reader.scan_line('A654 FETCH 2:4 (BODY[])'))
40
+
41
+ assert_equal('', @output.string)
42
+ end
43
+
44
+ def test_scan_line_string_literal
45
+ literal = <<-'EOF'
46
+ Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
47
+ From: Fred Foobar <foobar@Blurdybloop.COM>
48
+ Subject: afternoon meeting
49
+ To: mooch@owatagu.siam.edu
50
+ Message-Id: <B27397-0100000@Blurdybloop.COM>
51
+ MIME-Version: 1.0
52
+ Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
53
+
54
+ Hello Joe, do you think we can meet at 3:30 tomorrow?
55
+ EOF
56
+
57
+ line = 'A003 APPEND saved-messages (\Seen) ' + "{#{literal.bytesize}}"
58
+ @input.string = literal + "\r\n"
59
+
60
+ assert_equal([ 'A003', 'APPEND', 'saved-messages', '('.intern, '\Seen', ')'.intern, literal ], @reader.scan_line(line))
61
+ assert_equal('', @input.read)
62
+
63
+ cmd_cont_req = @output.string.each_line
64
+ assert_match(/^\+ /, cmd_cont_req.next)
65
+ assert_raise(StopIteration) { cmd_cont_req.next }
66
+ end
67
+
68
+ def test_read_line
69
+ assert_nil(@reader.read_line)
70
+
71
+ @input.string = "\n"
72
+ assert_equal([], @reader.read_line)
73
+
74
+ @input.string = "abcd CAPABILITY\n"
75
+ assert_equal(%w[ abcd CAPABILITY ], @reader.read_line)
76
+
77
+ @input.string = "abcd OK CAPABILITY completed\n"
78
+ assert_equal(%w[ abcd OK CAPABILITY completed ], @reader.read_line)
79
+
80
+ @input.string = "* CAPABILITY IMAP4rev1 AUTH=KERBEROS_V4\n"
81
+ assert_equal(%w[ * CAPABILITY IMAP4rev1 AUTH=KERBEROS_V4 ], @reader.read_line)
82
+
83
+ @input.string = "* 172 EXISTS\n"
84
+ assert_equal(%w[ * 172 EXISTS ], @reader.read_line)
85
+
86
+ @input.string = "* OK [UNSEEN 12] Message 12 is first unseen\n"
87
+ assert_equal([ '*', 'OK', '['.intern, 'UNSEEN', '12', ']'.intern, 'Message', '12', 'is', 'first', 'unseen', ], @reader.read_line)
88
+
89
+ @input.string = "* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\n"
90
+ assert_equal([ '*', 'FLAGS', '('.intern, '\Answered', '\Flagged', '\Deleted', '\Seen', '\Draft', ')'.intern ], @reader.read_line)
91
+
92
+ @input.string = "* OK [PERMANENTFLAGS (\\Deleted \\Seen \\*)] Limited\n"
93
+ assert_equal([ '*', 'OK',
94
+ '['.intern, 'PERMANENTFLAGS', '('.intern, '\Deleted', '\Seen', '\*', ')'.intern, ']'.intern,
95
+ 'Limited'
96
+ ], @reader.read_line)
97
+
98
+ @input.string = "A82 LIST \"\" *\n"
99
+ assert_equal([ 'A82', 'LIST', '', '*' ], @reader.read_line)
100
+
101
+ @input.string = "* LIST (\\Noselect) \"/\" foo\n"
102
+ assert_equal([ '*', 'LIST', '('.intern, '\Noselect', ')'.intern, '/', 'foo' ], @reader.read_line)
103
+
104
+ @input.string = "* LIST (\\Noselect) \"/\" \"foo [bar] (baz)\""
105
+ assert_equal([ '*', 'LIST', '('.intern, '\Noselect', ')'.intern, '/', 'foo [bar] (baz)' ], @reader.read_line)
106
+
107
+ @input.string = '* LIST (\Noselect) NIL ""'
108
+ assert_equal([ '*', 'LIST', '('.intern, '\Noselect', ')'.intern, :NIL, '' ], @reader.read_line)
109
+
110
+ @input.string = "A654 FETCH 2:4 (BODY[])\n"
111
+ assert_equal([ 'A654', 'FETCH', '2:4',
112
+ '('.intern,
113
+ [ :body, RIMS::Protocol.body(symbol: 'BODY', section: '') ],
114
+ ')'.intern
115
+ ],
116
+ @reader.read_line)
117
+
118
+ assert_equal('', @output.string)
119
+ end
120
+
121
+ def test_read_line_string_literal
122
+ literal = <<-'EOF'
123
+ Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
124
+ From: Fred Foobar <foobar@Blurdybloop.COM>
125
+ Subject: afternoon meeting
126
+ To: mooch@owatagu.siam.edu
127
+ Message-Id: <B27397-0100000@Blurdybloop.COM>
128
+ MIME-Version: 1.0
129
+ Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
130
+
131
+ Hello Joe, do you think we can meet at 3:30 tomorrow?
132
+ EOF
133
+
134
+ @input.string = "A003 APPEND saved-messages (\\Seen) {#{literal.bytesize}}\n" + literal + "\n"
135
+ assert_equal([ 'A003', 'APPEND', 'saved-messages', '('.intern, '\Seen', ')'.intern, literal ], @reader.read_line)
136
+ assert_equal('', @input.read)
137
+
138
+ cmd_cont_req = @output.string.each_line
139
+ assert_match(/^\+ /, cmd_cont_req.next)
140
+ assert_raise(StopIteration) { cmd_cont_req.next }
141
+ end
142
+
143
+ def test_read_line_string_literal_multi
144
+ literal1 = <<-'EOF'
145
+ Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
146
+ From: Fred Foobar <foobar@Blurdybloop.COM>
147
+ Subject: afternoon meeting
148
+ To: mooch@owatagu.siam.edu
149
+ Message-Id: <B27397-0100000@Blurdybloop.COM>
150
+ MIME-Version: 1.0
151
+ Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
152
+ EOF
153
+
154
+ literal2 = <<-'EOF'
155
+ Hello Joe, do you think we can meet at 3:30 tomorrow?
156
+ EOF
157
+
158
+ @input.string = "* ({#{literal1.bytesize}}\n" + literal1 + " {#{literal2.bytesize}}\n" + literal2 + ")\n"
159
+ assert_equal([ '*', '('.intern, literal1, literal2, ')'.intern ], @reader.read_line)
160
+ assert_equal('', @input.read)
161
+
162
+ cmd_cont_req = @output.string.each_line
163
+ assert_match(/^\+ /, cmd_cont_req.next)
164
+ assert_match(/^\+ /, cmd_cont_req.next)
165
+ assert_raise(StopIteration) { cmd_cont_req.next }
166
+ end
167
+
168
+ def test_parse
169
+ assert_equal([], @reader.parse([]))
170
+ assert_equal(%w[ abcd CAPABILITY ], @reader.parse(%w[ abcd CAPABILITY ]))
171
+ assert_equal(%w[ abcd OK CAPABILITY completed ], @reader.parse(%w[ abcd OK CAPABILITY completed ]))
172
+ assert_equal([ '*', 'OK', [ :block, 'UNSEEN', '12' ], 'Message', '12', 'is', 'first', 'unseen' ],
173
+ @reader.parse([ '*', 'OK', '['.intern, 'UNSEEN', '12', ']'.intern, 'Message', '12', 'is', 'first', 'unseen' ]))
174
+ assert_equal([ '*', 'FLAGS', [ :group, '\Answered', '\Flagged', '\Deleted', '\Seen', '\Draft' ] ],
175
+ @reader.parse([ '*', 'FLAGS', '('.intern, '\Answered', '\Flagged', '\Deleted', '\Seen', '\Draft', ')'.intern ]))
176
+ assert_equal([ '*', 'OK', [ :block, 'PERMANENTFLAGS', [ :group, '\Deleted', '\Seen', '\*' ] ], 'Limited' ],
177
+ @reader.parse([ '*', 'OK', '['.intern, 'PERMANENTFLAGS', '('.intern, '\Deleted', '\Seen', '\*', ')'.intern, ']'.intern, 'Limited' ]))
178
+ assert_equal([ '*', 'LIST', [ :group, '\Noselect' ], :NIL, '' ],
179
+ @reader.parse([ '*', 'LIST', '('.intern, '\Noselect', ')'.intern, :NIL, '' ]))
180
+ assert_equal([ 'A654', 'FETCH', '2:4',
181
+ [ :group,
182
+ [ :body,
183
+ RIMS::Protocol.body(symbol: 'BODY',
184
+ section: '',
185
+ section_list: [])
186
+ ]
187
+ ]
188
+ ],
189
+ @reader.parse([ 'A654', 'FETCH', '2:4',
190
+ '('.intern,
191
+ [ :body, RIMS::Protocol.body(symbol: 'BODY', section: '') ],
192
+ ')'.intern
193
+ ]))
194
+ assert_equal([ 'A003', 'APPEND', 'saved-messages', "foo\nbody[]\nbar\n" ],
195
+ @reader.parse([ 'A003', 'APPEND', 'saved-messages', "foo\nbody[]\nbar\n" ]))
196
+
197
+ assert_equal('', @output.string)
198
+ end
199
+
200
+ def test_read_command
201
+ assert_nil(@reader.read_command)
202
+
203
+ @input.string = "\n"
204
+ assert_nil(@reader.read_command)
205
+
206
+ @input.string = " \t\n"
207
+ assert_nil(@reader.read_command)
208
+
209
+ @input.string = "abcd CAPABILITY\n"
210
+ assert_equal(%w[ abcd CAPABILITY ], @reader.read_command)
211
+
212
+ @input.string = "\n \n\t\nabcd CAPABILITY\n"
213
+ assert_equal(%w[ abcd CAPABILITY ], @reader.read_command)
214
+
215
+ @input.string = "abcd OK CAPABILITY completed\n"
216
+ assert_equal(%w[ abcd OK CAPABILITY completed ], @reader.read_command)
217
+
218
+ @input.string = "A003 STORE 2:4 +FLAGS (\\Deleted)\n"
219
+ assert_equal([ 'A003', 'STORE', '2:4', '+FLAGS', [ :group, '\Deleted' ] ], @reader.read_command)
220
+
221
+ @input.string = "abcd SEARCH (OR (FROM foo) (FROM bar))\n"
222
+ assert_equal([ 'abcd', 'SEARCH',
223
+ [ :group,
224
+ 'OR',
225
+ [ :group, 'FROM', 'foo' ],
226
+ [ :group, 'FROM', 'bar' ]
227
+ ]
228
+ ],
229
+ @reader.read_command)
230
+
231
+ @input.string = "abcd SEARCH SUBJECT \"NIL\"\n"
232
+ assert_equal([ 'abcd', 'SEARCH', 'SUBJECT', 'NIL' ], @reader.read_command)
233
+
234
+ @input.string = "abcd SEARCH SUBJECT \"(\"\n"
235
+ assert_equal([ 'abcd', 'SEARCH', 'SUBJECT', '(' ], @reader.read_command)
236
+
237
+ @input.string = "abcd SEARCH SUBJECT \")\"\n"
238
+ assert_equal([ 'abcd', 'SEARCH', 'SUBJECT', ')' ], @reader.read_command)
239
+
240
+ @input.string = "abcd SEARCH SUBJECT \"[\"\n"
241
+ assert_equal([ 'abcd', 'SEARCH', 'SUBJECT', '[' ], @reader.read_command)
242
+
243
+ @input.string = "abcd SEARCH SUBJECT \"]\"\n"
244
+ assert_equal([ 'abcd', 'SEARCH', 'SUBJECT', ']' ], @reader.read_command)
245
+
246
+ @input.string = "A654 FETCH 2:4 (BODY)\n"
247
+ assert_equal([ 'A654', 'FETCH', '2:4', [ :group, 'BODY' ] ], @reader.read_command)
248
+
249
+ @input.string = "A654 FETCH 2:4 (BODY[])\n"
250
+ assert_equal([ 'A654', 'FETCH', '2:4', [
251
+ :group, [
252
+ :body,
253
+ RIMS::Protocol.body(symbol: 'BODY',
254
+ section: '',
255
+ section_list: [])
256
+ ]
257
+ ]
258
+ ], @reader.read_command)
259
+
260
+ @input.string = "A654 FETCH 2:4 (FLAGS BODY.PEEK[HEADER.FIELDS (DATE FROM)]<0.1500>)\n"
261
+ assert_equal([ 'A654', 'FETCH', '2:4',
262
+ [ :group,
263
+ 'FLAGS',
264
+ [ :body,
265
+ RIMS::Protocol.body(symbol: 'BODY',
266
+ option: 'PEEK',
267
+ section: 'HEADER.FIELDS (DATE FROM)',
268
+ section_list: [ 'HEADER.FIELDS', [ :group, 'DATE', 'FROM' ] ],
269
+ partial_origin: 0,
270
+ partial_size: 1500)
271
+ ]
272
+ ]
273
+ ],
274
+ @reader.read_command)
275
+
276
+ @input.string = "A654 APPEND saved-messages \"body[]\"\n"
277
+ assert_equal([ 'A654', 'APPEND', 'saved-messages', 'body[]' ], @reader.read_command)
278
+
279
+ assert_equal('', @output.string)
280
+
281
+ literal = <<-'EOF'
282
+ Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
283
+ From: Fred Foobar <foobar@Blurdybloop.COM>
284
+ Subject: afternoon meeting
285
+ To: mooch@owatagu.siam.edu
286
+ Message-Id: <B27397-0100000@Blurdybloop.COM>
287
+ MIME-Version: 1.0
288
+ Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
289
+
290
+ Hello Joe, do you think we can meet at 3:30 tomorrow?
291
+ EOF
292
+
293
+ @input.string = "A003 APPEND saved-messages (\\Seen) {#{literal.bytesize}}\n" + literal + "\n"
294
+ @output.string = ''
295
+ assert_equal([ 'A003', 'APPEND', 'saved-messages', [ :group, '\Seen' ], literal ], @reader.read_command)
296
+
297
+ cmd_cont_req = @output.string.each_line
298
+ assert_match(/^\+ /, cmd_cont_req.next)
299
+ assert_raise(StopIteration) { cmd_cont_req.next }
300
+
301
+
302
+ literal2 = <<-'EOF'
303
+ Subject: parse test
304
+
305
+ body[]
306
+ EOF
307
+
308
+ @input.string = "A004 APPEND saved-messages {#{literal2.bytesize}}\n" + literal2 + "\n"
309
+ @output.string = ''
310
+ assert_equal([ 'A004', 'APPEND', 'saved-messages', literal2 ], @reader.read_command)
311
+
312
+ cmd_cont_req = @output.string.each_line
313
+ assert_match(/^\+ /, cmd_cont_req.next)
314
+ assert_raise(StopIteration) { cmd_cont_req.next }
315
+
316
+ literal3 = 'body[]'
317
+
318
+ @input.string = "A005 APPEND saved-messages {#{literal3.bytesize}}\n" + literal3 + "\n"
319
+ @output.string = ''
320
+ assert_equal([ 'A005', 'APPEND', 'saved-messages', literal3 ], @reader.read_command)
321
+
322
+ cmd_cont_req = @output.string.each_line
323
+ assert_match(/^\+ /, cmd_cont_req.next)
324
+ assert_raise(StopIteration) { cmd_cont_req.next }
325
+ end
326
+ end
327
+ end
328
+
329
+ # Local Variables:
330
+ # mode: Ruby
331
+ # indent-tabs-mode: nil
332
+ # End:
@@ -0,0 +1,974 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rims'
4
+ require 'test/unit'
5
+ require 'time'
6
+
7
+ module RIMS::Test
8
+ class ProtocolSearchParserTest < Test::Unit::TestCase
9
+ def setup
10
+ @kv_store = {}
11
+ @kvs_open = proc{|path| RIMS::Hash_KeyValueStore.new(@kv_store[path] = {}) }
12
+ @mail_store = RIMS::MailStore.new(RIMS::DB::Meta.new(@kvs_open.call('meta')),
13
+ RIMS::DB::Message.new(@kvs_open.call('msg'))) {|mbox_id|
14
+ RIMS::DB::Mailbox.new(@kvs_open.call("mbox_#{mbox_id}"))
15
+ }
16
+ @inbox_id = @mail_store.add_mbox('INBOX')
17
+ end
18
+
19
+ def add_msg(msg_txt, *optional_args)
20
+ @mail_store.add_msg(@inbox_id, msg_txt, *optional_args)
21
+ end
22
+ private :add_msg
23
+
24
+ def get_msg_flag(uid, flag_name)
25
+ @mail_store.msg_flag(@inbox_id, uid, flag_name)
26
+ end
27
+ private :get_msg_flag
28
+
29
+ def set_msg_flag(uid, flag_name, flag_value)
30
+ @mail_store.set_msg_flag(@inbox_id, uid, flag_name, flag_value)
31
+ nil
32
+ end
33
+ private :set_msg_flag
34
+
35
+ def expunge(*uid_list)
36
+ for uid in uid_list
37
+ set_msg_flag(uid, 'deleted', true)
38
+ end
39
+ @mail_store.expunge_mbox(@inbox_id)
40
+ nil
41
+ end
42
+ private :expunge
43
+
44
+ def assert_msg_uid(*uid_list)
45
+ assert_equal(uid_list, @mail_store.each_msg_uid(@inbox_id).to_a)
46
+ end
47
+ private :assert_msg_uid
48
+
49
+ def assert_msg_flag(flag_name, *flag_value_list)
50
+ uid_list = @mail_store.each_msg_uid(@inbox_id).to_a
51
+ assert_equal(uid_list.map{|uid| get_msg_flag(uid, flag_name) }, flag_value_list)
52
+ end
53
+ private :assert_msg_flag
54
+
55
+ def make_search_parser(charset: nil)
56
+ yield
57
+ @folder = @mail_store.select_mbox(@inbox_id).reload
58
+ @parser = RIMS::Protocol::SearchParser.new(@mail_store, @folder)
59
+ @parser.charset = charset if charset
60
+ nil
61
+ end
62
+ private :make_search_parser
63
+
64
+ def parse_search_key(search_key_list)
65
+ @cond = @parser.parse(search_key_list)
66
+ begin
67
+ yield
68
+ ensure
69
+ @cond = nil
70
+ end
71
+ end
72
+ private :parse_search_key
73
+
74
+ def assert_search_cond(msg_idx, expected_found_flag)
75
+ assert_equal(expected_found_flag, @cond.call(@folder[msg_idx]))
76
+ end
77
+ private :assert_search_cond
78
+
79
+ def assert_search_syntax_error(search_key_list)
80
+ assert_raise(RIMS::SyntaxError) {
81
+ @parser.parse(search_key_list)
82
+ }
83
+ end
84
+ private :assert_search_syntax_error
85
+
86
+ def test_parse_all
87
+ make_search_parser{
88
+ add_msg('foo')
89
+ assert_msg_uid(1)
90
+ }
91
+
92
+ parse_search_key([ 'ALL' ]) {
93
+ assert_search_cond(0, true)
94
+ }
95
+ end
96
+
97
+ def test_parse_answered
98
+ make_search_parser{
99
+ add_msg('foo')
100
+ add_msg('foo')
101
+ assert_msg_uid(1, 2)
102
+
103
+ set_msg_flag(1, 'answered', true)
104
+ assert_msg_flag('answered', true, false)
105
+ }
106
+
107
+ parse_search_key([ 'ANSWERED' ]) {
108
+ assert_search_cond(0, true)
109
+ assert_search_cond(1, false)
110
+ }
111
+ end
112
+
113
+ def test_parse_bcc
114
+ make_search_parser{
115
+ add_msg("Bcc: foo\r\n" +
116
+ "\r\n" +
117
+ "foo")
118
+ add_msg("Bcc: bar\r\n" +
119
+ "\r\n" +
120
+ "foo")
121
+ add_msg('foo')
122
+ assert_msg_uid(1, 2, 3)
123
+ }
124
+
125
+ parse_search_key([ 'BCC', 'foo' ]) {
126
+ assert_search_cond(0, true)
127
+ assert_search_cond(1, false)
128
+ assert_search_cond(2, false)
129
+ }
130
+
131
+ assert_search_syntax_error([ 'BCC' ])
132
+ assert_search_syntax_error([ 'BCC', [ :group, 'foo' ] ])
133
+ end
134
+
135
+ def test_parse_before
136
+ make_search_parser{
137
+ add_msg('foo', Time.parse('2013-11-07 12:34:56'))
138
+ add_msg('foo', Time.parse('2013-11-08 12:34:56'))
139
+ add_msg('foo', Time.parse('2013-11-09 12:34:56'))
140
+ assert_msg_uid(1, 2, 3)
141
+ }
142
+
143
+ parse_search_key([ 'BEFORE', '08-Nov-2013' ]) {
144
+ assert_search_cond(0, true)
145
+ assert_search_cond(1, false)
146
+ assert_search_cond(2, false)
147
+ }
148
+
149
+ assert_search_syntax_error([ 'BEFORE' ])
150
+ assert_search_syntax_error([ 'BEFORE', '99-Nov-2013' ])
151
+ assert_search_syntax_error([ 'BEFORE', [ :group, '08-Nov-2013'] ])
152
+ end
153
+
154
+ def test_parse_body
155
+ make_search_parser{
156
+ add_msg("Content-Type: text/plain\r\n" +
157
+ "\r\n" +
158
+ "foo")
159
+ add_msg("Content-Type: text/plain\r\n" +
160
+ "\r\n" +
161
+ "bar")
162
+ add_msg("Content-Type: message/rfc822\r\n" +
163
+ "\r\n" +
164
+ "foo")
165
+ add_msg(<<-'EOF')
166
+ Content-Type: multipart/alternative; boundary="1383.905529.351297"
167
+
168
+ --1383.905529.351297
169
+ Content-Type: text/plain
170
+
171
+ foo
172
+ --1383.905529.351297
173
+ Content-Type: text/html
174
+
175
+ <html><body><p>foo</p></body></html>
176
+ --1383.905529.351297--
177
+ EOF
178
+
179
+ assert_msg_uid(1, 2, 3, 4)
180
+ }
181
+
182
+ parse_search_key([ 'BODY', 'foo' ]) {
183
+ assert_search_cond(0, true)
184
+ assert_search_cond(1, false)
185
+ assert_search_cond(2, true)
186
+ assert_search_cond(3, false) # ignored text part of multipart message.
187
+ }
188
+
189
+ assert_search_syntax_error([ 'BODY' ])
190
+ assert_search_syntax_error([ 'BODY', [ :group, 'foo' ] ])
191
+ end
192
+
193
+ def test_parse_cc
194
+ make_search_parser{
195
+ add_msg("Cc: foo\r\n" +
196
+ "\r\n" +
197
+ "foo")
198
+ add_msg("Cc: bar\r\n" +
199
+ "\r\n" +
200
+ "foo")
201
+ add_msg('foo')
202
+ assert_msg_uid(1, 2, 3)
203
+ }
204
+
205
+ parse_search_key([ 'CC', 'foo' ]) {
206
+ assert_search_cond(0, true)
207
+ assert_search_cond(1, false)
208
+ assert_search_cond(2, false)
209
+ }
210
+
211
+ assert_search_syntax_error([ 'CC' ])
212
+ assert_search_syntax_error([ 'CC', [ :group, 'foo' ] ])
213
+ end
214
+
215
+ def test_parse_deleted
216
+ make_search_parser{
217
+ add_msg('foo')
218
+ add_msg('foo')
219
+ assert_msg_uid(1, 2)
220
+
221
+ set_msg_flag(1, 'deleted', true)
222
+ assert_msg_flag('deleted', true, false)
223
+ }
224
+
225
+ parse_search_key([ 'DELETED' ]) {
226
+ assert_search_cond(0, true)
227
+ assert_search_cond(1, false)
228
+ }
229
+ end
230
+
231
+ def test_parse_draft
232
+ make_search_parser{
233
+ add_msg('foo')
234
+ add_msg('foo')
235
+ assert_msg_uid(1, 2)
236
+
237
+ set_msg_flag(1, 'draft', true)
238
+ assert_msg_flag('draft', true, false)
239
+ }
240
+
241
+ parse_search_key([ 'DRAFT' ]) {
242
+ assert_search_cond(0, true)
243
+ assert_search_cond(1, false)
244
+ }
245
+ end
246
+
247
+ def test_parse_flagged
248
+ make_search_parser{
249
+ add_msg('foo')
250
+ add_msg('foo')
251
+ assert_msg_uid(1, 2)
252
+
253
+ set_msg_flag(1, 'flagged', true)
254
+ assert_msg_flag('flagged', true, false)
255
+ }
256
+
257
+ parse_search_key([ 'FLAGGED' ]) {
258
+ assert_search_cond(0, true)
259
+ assert_search_cond(1, false)
260
+ }
261
+ end
262
+
263
+ def test_parse_from
264
+ make_search_parser{
265
+ add_msg("From: foo\r\n" +
266
+ "\r\n" +
267
+ "foo")
268
+ add_msg("From: bar\r\n" +
269
+ "\r\n" +
270
+ "foo")
271
+ add_msg('foo')
272
+ assert_msg_uid(1, 2, 3)
273
+ }
274
+
275
+ parse_search_key([ 'FROM', 'foo' ]) {
276
+ assert_search_cond(0, true)
277
+ assert_search_cond(1, false)
278
+ assert_search_cond(2, false)
279
+ }
280
+
281
+ assert_search_syntax_error([ 'FROM' ])
282
+ assert_search_syntax_error([ 'FROM', [ :group, 'foo' ] ])
283
+ end
284
+
285
+ def test_parse_header
286
+ make_search_parser{
287
+ add_msg("X-Foo: alice\r\n" +
288
+ "X-Bar: bob\r\n" +
289
+ "\r\n" +
290
+ "foo")
291
+ add_msg("X-Foo: bob\r\n" +
292
+ "X-Bar: alice\r\n" +
293
+ "\r\n" +
294
+ "foo")
295
+ add_msg('foo')
296
+ assert_msg_uid(1, 2, 3)
297
+ }
298
+
299
+ parse_search_key([ 'HEADER', 'x-foo', 'alice' ]) {
300
+ assert_search_cond(0, true)
301
+ assert_search_cond(1, false)
302
+ assert_search_cond(2, false)
303
+ }
304
+
305
+ parse_search_key([ 'HEADER', 'x-foo', 'bob' ]) {
306
+ assert_search_cond(0, false)
307
+ assert_search_cond(1, true)
308
+ assert_search_cond(2, false)
309
+ }
310
+
311
+ parse_search_key([ 'HEADER', 'x-bar', 'alice' ]) {
312
+ assert_search_cond(0, false)
313
+ assert_search_cond(1, true)
314
+ assert_search_cond(2, false)
315
+ }
316
+
317
+ parse_search_key([ 'HEADER', 'x-bar', 'bob' ]) {
318
+ assert_search_cond(0, true)
319
+ assert_search_cond(1, false)
320
+ assert_search_cond(2, false)
321
+ }
322
+
323
+ assert_search_syntax_error([ 'HEADER' ])
324
+ assert_search_syntax_error([ 'HEADER', 'Received' ])
325
+ assert_search_syntax_error([ 'HEADER', 'Received', [ :group, 'foo' ] ])
326
+ assert_search_syntax_error([ 'HEADER', [ :group, 'Received' ], 'foo' ])
327
+ end
328
+
329
+ def test_parse_keyword
330
+ make_search_parser{
331
+ add_msg('')
332
+ assert_msg_uid(1)
333
+ }
334
+
335
+ parse_search_key([ 'KEYWORD', 'foo' ]) {
336
+ assert_search_cond(0, false) # always false
337
+ }
338
+
339
+ assert_search_syntax_error([ 'KEYWORD' ])
340
+ assert_search_syntax_error([ 'KEYWORD', [ :group, 'foo' ] ])
341
+ end
342
+
343
+ def test_parse_larger
344
+ make_search_parser{
345
+ add_msg('foo')
346
+ add_msg('1234')
347
+ add_msg('bar')
348
+ assert_msg_uid(1, 2, 3)
349
+ }
350
+
351
+ parse_search_key([ 'LARGER', '3' ]) {
352
+ assert_search_cond(0, false)
353
+ assert_search_cond(1, true)
354
+ assert_search_cond(2, false)
355
+ }
356
+
357
+ assert_search_syntax_error([ 'LARGER' ])
358
+ assert_search_syntax_error([ 'LARGER', [ :group, '3' ] ])
359
+ assert_search_syntax_error([ 'LARGER', 'nonum' ])
360
+ end
361
+
362
+ def test_parse_new
363
+ make_search_parser{
364
+ add_msg('foo')
365
+ add_msg('bar')
366
+ add_msg('baz')
367
+ assert_msg_uid(1, 2, 3)
368
+
369
+ set_msg_flag(3, 'recent', false)
370
+ set_msg_flag(2, 'seen', true)
371
+ assert_msg_flag('recent', true, true, false)
372
+ assert_msg_flag('seen', false, true, false)
373
+ }
374
+
375
+ parse_search_key([ 'NEW' ]) {
376
+ assert_search_cond(0, true)
377
+ assert_search_cond(1, false)
378
+ assert_search_cond(2, false)
379
+ }
380
+ end
381
+
382
+ def test_parse_not
383
+ make_search_parser{
384
+ add_msg('foo')
385
+ add_msg('1234')
386
+ add_msg('bar')
387
+ assert_msg_uid(1, 2, 3)
388
+
389
+ set_msg_flag(1, 'answered', true)
390
+ assert_msg_flag('answered', true, false, false)
391
+ }
392
+
393
+ parse_search_key([ 'NOT', 'LARGER', '3' ]) {
394
+ assert_search_cond(0, true)
395
+ assert_search_cond(1, false)
396
+ assert_search_cond(2, true)
397
+ }
398
+
399
+ parse_search_key([ 'NOT', 'ANSWERED' ]) {
400
+ assert_search_cond(0, false)
401
+ assert_search_cond(1, true)
402
+ assert_search_cond(2, true)
403
+ }
404
+
405
+ assert_search_syntax_error([ 'NOT' ])
406
+ end
407
+
408
+ def test_parse_old
409
+ make_search_parser{
410
+ add_msg('foo')
411
+ add_msg('bar')
412
+ assert_msg_uid(1, 2)
413
+
414
+ set_msg_flag(1, 'recent', false)
415
+ assert_msg_flag('recent', false, true)
416
+ }
417
+
418
+ parse_search_key([ 'OLD' ]) {
419
+ assert_search_cond(0, true)
420
+ assert_search_cond(1, false)
421
+ }
422
+ end
423
+
424
+ def test_parse_on
425
+ make_search_parser{
426
+ add_msg('foo', Time.parse('2013-11-07 12:34:56'))
427
+ add_msg('foo', Time.parse('2013-11-08 12:34:56'))
428
+ add_msg('foo', Time.parse('2013-11-09 12:34:56'))
429
+ assert_msg_uid(1, 2, 3)
430
+ }
431
+
432
+ parse_search_key([ 'ON', '08-Nov-2013' ]) {
433
+ assert_search_cond(0, false)
434
+ assert_search_cond(1, true)
435
+ assert_search_cond(2, false)
436
+ }
437
+
438
+ assert_search_syntax_error([ 'ON' ])
439
+ assert_search_syntax_error([ 'ON', '99-Nov-2013' ])
440
+ assert_search_syntax_error([ 'ON', [ :group, '08-Nov-2013'] ])
441
+ end
442
+
443
+ def test_parse_or
444
+ make_search_parser{
445
+ add_msg('foo')
446
+ add_msg('foo')
447
+ add_msg('foo')
448
+ add_msg('foo')
449
+ assert_msg_uid(1, 2, 3, 4)
450
+
451
+ set_msg_flag(1, 'answered', true)
452
+ set_msg_flag(2, 'answered', true)
453
+ set_msg_flag(1, 'flagged', true)
454
+ set_msg_flag(3, 'flagged', true)
455
+ assert_msg_flag('answered', true, true, false, false)
456
+ assert_msg_flag('flagged', true, false, true, false)
457
+ }
458
+
459
+ parse_search_key([ 'OR', 'ANSWERED', 'FLAGGED' ]) {
460
+ assert_search_cond(0, true)
461
+ assert_search_cond(1, true)
462
+ assert_search_cond(2, true)
463
+ assert_search_cond(3, false)
464
+
465
+ }
466
+
467
+ assert_search_syntax_error([ 'OR' ])
468
+ assert_search_syntax_error([ 'OR', 'ANSWERED' ])
469
+ end
470
+
471
+ def test_parse_recent
472
+ make_search_parser{
473
+ add_msg('foo')
474
+ add_msg('foo')
475
+ assert_msg_uid(1, 2)
476
+
477
+ set_msg_flag(1, 'recent', false)
478
+ assert_msg_flag('recent', false, true)
479
+ }
480
+
481
+ parse_search_key([ 'RECENT' ]) {
482
+ assert_search_cond(0, false)
483
+ assert_search_cond(1, true)
484
+ }
485
+ end
486
+
487
+ def test_parse_seen
488
+ make_search_parser{
489
+ add_msg('foo')
490
+ add_msg('foo')
491
+ assert_msg_uid(1, 2)
492
+
493
+ set_msg_flag(1, 'seen', true)
494
+ assert_msg_flag('seen', true, false)
495
+ }
496
+
497
+ parse_search_key([ 'SEEN' ]) {
498
+ assert_search_cond(0, true)
499
+ assert_search_cond(1, false)
500
+ }
501
+ end
502
+
503
+ def test_parse_sentbefore
504
+ make_search_parser{
505
+ add_msg("Date: Thu, 07 Nov 2013 12:34:56 +0900\r\n" +
506
+ "\r\n" +
507
+ "foo")
508
+ add_msg("Date: Fri, 08 Nov 2013 12:34:56 +0900\r\n" +
509
+ "\r\n" +
510
+ "foo")
511
+ add_msg("Date: Sat, 09 Nov 2013 12:34:56 +0900\r\n" +
512
+ "\r\n" +
513
+ "foo")
514
+ add_msg('foo')
515
+ assert_msg_uid(1, 2, 3, 4)
516
+ }
517
+
518
+ parse_search_key([ 'SENTBEFORE', '08-Nov-2013' ]) {
519
+ assert_search_cond(0, true)
520
+ assert_search_cond(1, false)
521
+ assert_search_cond(2, false)
522
+ assert_search_cond(3, false)
523
+ }
524
+
525
+ assert_search_syntax_error([ 'SENTBEFORE' ])
526
+ assert_search_syntax_error([ 'SENTBEFORE', '99-Nov-2013' ])
527
+ assert_search_syntax_error([ 'SENTBEFORE', [ :group, '08-Nov-2013'] ])
528
+ end
529
+
530
+ def test_parse_senton
531
+ make_search_parser{
532
+ add_msg("Date: Thu, 07 Nov 2013 12:34:56 +0900\r\n" +
533
+ "\r\n" +
534
+ "foo")
535
+ add_msg("Date: Fri, 08 Nov 2013 12:34:56 +0900\r\n" +
536
+ "\r\n" +
537
+ "foo")
538
+ add_msg("Date: Sat, 09 Nov 2013 12:34:56 +0900\r\n" +
539
+ "\r\n" +
540
+ "foo")
541
+ add_msg('foo')
542
+ assert_msg_uid(1, 2, 3, 4)
543
+ }
544
+
545
+ parse_search_key([ 'SENTON', '08-Nov-2013' ]) {
546
+ assert_search_cond(0, false)
547
+ assert_search_cond(1, true)
548
+ assert_search_cond(2, false)
549
+ assert_search_cond(3, false)
550
+ }
551
+
552
+ assert_search_syntax_error([ 'SENTON' ])
553
+ assert_search_syntax_error([ 'SENTON', '99-Nov-2013' ])
554
+ assert_search_syntax_error([ 'SENTON', [ :group, '08-Nov-2013'] ])
555
+ end
556
+
557
+ def test_parse_sentsince
558
+ make_search_parser{
559
+ add_msg("Date: Thu, 07 Nov 2013 12:34:56 +0900\r\n" +
560
+ "\r\n" +
561
+ "foo")
562
+ add_msg("Date: Fri, 08 Nov 2013 12:34:56 +0900\r\n" +
563
+ "\r\n" +
564
+ "foo")
565
+ add_msg("Date: Sat, 09 Nov 2013 12:34:56 +0900\r\n" +
566
+ "\r\n" +
567
+ "foo")
568
+ add_msg('foo')
569
+ assert_msg_uid(1, 2, 3, 4)
570
+ }
571
+
572
+ parse_search_key([ 'SENTSINCE', '08-Nov-2013' ]) {
573
+ assert_search_cond(0, false)
574
+ assert_search_cond(1, false)
575
+ assert_search_cond(2, true)
576
+ assert_search_cond(3, false)
577
+ }
578
+
579
+ assert_search_syntax_error([ 'SENTSINCE' ])
580
+ assert_search_syntax_error([ 'SENTSINCE', '99-Nov-2013' ])
581
+ assert_search_syntax_error([ 'SENTSINCE', [ :group, '08-Nov-2013'] ])
582
+ end
583
+
584
+ def test_parse_since
585
+ make_search_parser{
586
+ add_msg('foo', Time.parse('2013-11-07 12:34:56'))
587
+ add_msg('foo', Time.parse('2013-11-08 12:34:56'))
588
+ add_msg('foo', Time.parse('2013-11-09 12:34:56'))
589
+ assert_msg_uid(1, 2, 3)
590
+ }
591
+
592
+ parse_search_key([ 'SINCE', '08-Nov-2013' ]) {
593
+ assert_search_cond(0, false)
594
+ assert_search_cond(1, false)
595
+ assert_search_cond(2, true)
596
+ }
597
+
598
+ assert_search_syntax_error([ 'SINCE' ])
599
+ assert_search_syntax_error([ 'SINCE', '99-Nov-2013' ])
600
+ assert_search_syntax_error([ 'SINCE', [ :group, '08-Nov-2013'] ])
601
+ end
602
+
603
+ def test_parse_smaller
604
+ make_search_parser{
605
+ add_msg('foo')
606
+ add_msg('12')
607
+ add_msg('bar')
608
+ assert_msg_uid(1, 2, 3)
609
+ }
610
+
611
+ parse_search_key([ 'SMALLER', '3' ]) {
612
+ assert_search_cond(0, false)
613
+ assert_search_cond(1, true)
614
+ assert_search_cond(2, false)
615
+ }
616
+
617
+ assert_search_syntax_error([ 'SMALLER' ])
618
+ assert_search_syntax_error([ 'SMALLER', [ :group, '3' ] ])
619
+ assert_search_syntax_error([ 'SMALLER', 'nonum' ])
620
+ end
621
+
622
+ def test_parse_subject
623
+ make_search_parser{
624
+ add_msg("Subject: foo\r\n" +
625
+ "\r\n" +
626
+ "foo")
627
+ add_msg("Subject: bar\r\n" +
628
+ "\r\n" +
629
+ "foo")
630
+ add_msg('foo')
631
+ assert_msg_uid(1, 2, 3)
632
+ }
633
+
634
+ parse_search_key([ 'SUBJECT', 'foo' ]) {
635
+ assert_search_cond(0, true)
636
+ assert_search_cond(1, false)
637
+ assert_search_cond(2, false)
638
+ }
639
+
640
+ assert_search_syntax_error([ 'SUBJECT' ])
641
+ assert_search_syntax_error([ 'SUBJECT', [ :group, 'foo' ] ])
642
+ end
643
+
644
+ def test_parse_text
645
+ make_search_parser{
646
+ add_msg("Content-Type: text/plain\r\n" +
647
+ "Subject: foo\r\n" +
648
+ "\r\n" +
649
+ "bar")
650
+ assert_msg_uid(1)
651
+ }
652
+
653
+ parse_search_key([ 'TEXT', 'jec' ]) {
654
+ assert_search_cond(0, true)
655
+ }
656
+ parse_search_key([ 'TEXT', 'foo' ]) {
657
+ assert_search_cond(0, true)
658
+ }
659
+ parse_search_key([ 'TEXT', 'bar' ]) {
660
+ assert_search_cond(0, true)
661
+ }
662
+ parse_search_key([ 'TEXT', 'baz' ]) {
663
+ assert_search_cond(0, false)
664
+ }
665
+
666
+ assert_search_syntax_error([ 'TEXT' ])
667
+ assert_search_syntax_error([ 'TEXT', [ :group, 'foo'] ])
668
+ end
669
+
670
+ def test_parse_to
671
+ make_search_parser{
672
+ add_msg("To: foo\r\n" +
673
+ "\r\n" +
674
+ "foo")
675
+ add_msg("To: bar\r\n" +
676
+ "\r\n" +
677
+ "foo")
678
+ add_msg('foo')
679
+ assert_msg_uid(1, 2, 3)
680
+ }
681
+
682
+ parse_search_key([ 'TO', 'foo' ]) {
683
+ assert_search_cond(0, true)
684
+ assert_search_cond(1, false)
685
+ assert_search_cond(2, false)
686
+ }
687
+
688
+ assert_search_syntax_error([ 'TO' ])
689
+ assert_search_syntax_error([ 'TO', [ :group, 'foo' ] ])
690
+ end
691
+
692
+ def test_parse_uid
693
+ make_search_parser{
694
+ add_msg('foo')
695
+ add_msg('foo')
696
+ add_msg('foo')
697
+ add_msg('foo')
698
+ add_msg('foo')
699
+ add_msg('foo')
700
+ expunge(1, 3, 5)
701
+ assert_msg_uid(2, 4, 6)
702
+ }
703
+
704
+ parse_search_key([ 'UID', '2,*' ]) {
705
+ assert_search_cond(0, true)
706
+ assert_search_cond(1, false)
707
+ assert_search_cond(2, true)
708
+ }
709
+
710
+ begin
711
+ @parser.parse([ 'UID', 'detarame' ])
712
+ rescue
713
+ error = $!
714
+ end
715
+ assert_kind_of(RIMS::SyntaxError, error)
716
+ end
717
+
718
+ def test_parse_unanswered
719
+ make_search_parser{
720
+ add_msg('foo')
721
+ add_msg('foo')
722
+ assert_msg_uid(1, 2)
723
+
724
+ set_msg_flag(1, 'answered', true)
725
+ assert_msg_flag('answered', true, false)
726
+ }
727
+
728
+ parse_search_key([ 'UNANSWERED' ]) {
729
+ assert_search_cond(0, false)
730
+ assert_search_cond(1, true)
731
+ }
732
+ end
733
+
734
+ def test_parse_undeleted
735
+ make_search_parser{
736
+ add_msg('foo')
737
+ add_msg('foo')
738
+ assert_msg_uid(1, 2)
739
+
740
+ set_msg_flag(1, 'deleted', true)
741
+ assert_msg_flag('deleted', true, false)
742
+ }
743
+
744
+ parse_search_key([ 'UNDELETED' ]) {
745
+ assert_search_cond(0, false)
746
+ assert_search_cond(1, true)
747
+ }
748
+ end
749
+
750
+ def test_parse_undraft
751
+ make_search_parser{
752
+ add_msg('foo')
753
+ add_msg('foo')
754
+ assert_msg_uid(1, 2)
755
+
756
+ set_msg_flag(1, 'draft', true)
757
+ assert_msg_flag('draft', true, false)
758
+ }
759
+
760
+ parse_search_key([ 'UNDRAFT' ]) {
761
+ assert_search_cond(0, false)
762
+ assert_search_cond(1, true)
763
+ }
764
+ end
765
+
766
+ def test_parse_unflagged
767
+ make_search_parser{
768
+ add_msg('foo')
769
+ add_msg('foo')
770
+ assert_msg_uid(1, 2)
771
+
772
+ set_msg_flag(1, 'flagged', true)
773
+ assert_msg_flag('flagged', true, false)
774
+ }
775
+
776
+ parse_search_key([ 'UNFLAGGED' ]) {
777
+ assert_search_cond(0, false)
778
+ assert_search_cond(1, true)
779
+ }
780
+ end
781
+
782
+ def test_parse_unkeyword
783
+ make_search_parser{
784
+ add_msg('')
785
+ assert_msg_uid(1)
786
+ }
787
+
788
+ parse_search_key([ 'UNKEYWORD', 'foo' ]) {
789
+ assert_search_cond(0, true) # always true
790
+ }
791
+
792
+ assert_search_syntax_error([ 'UNKEYWORD' ])
793
+ assert_search_syntax_error([ 'UNKEYWORD', [ :group, 'foo' ] ])
794
+ end
795
+
796
+ def test_parse_unseen
797
+ make_search_parser{
798
+ add_msg('foo')
799
+ add_msg('foo')
800
+ assert_msg_uid(1, 2)
801
+
802
+ set_msg_flag(1, 'seen', true)
803
+ assert_msg_flag('seen', true, false)
804
+ }
805
+
806
+ parse_search_key([ 'UNSEEN' ]) {
807
+ assert_search_cond(0, false)
808
+ assert_search_cond(1, true)
809
+ }
810
+ end
811
+
812
+ def test_parse_msg_set
813
+ make_search_parser{
814
+ add_msg('foo')
815
+ add_msg('foo')
816
+ add_msg('foo')
817
+ add_msg('foo')
818
+ add_msg('foo')
819
+ add_msg('foo')
820
+ expunge(1, 3, 5)
821
+ assert_msg_uid(2, 4, 6)
822
+ }
823
+
824
+ parse_search_key([ '1,*' ]) {
825
+ assert_search_cond(0, true)
826
+ assert_search_cond(1, false)
827
+ assert_search_cond(2, true)
828
+ }
829
+
830
+ assert_search_syntax_error([ 'detarame' ])
831
+ end
832
+
833
+ def test_parse_group
834
+ make_search_parser{
835
+ add_msg('foo')
836
+ add_msg('foo')
837
+ add_msg('foo')
838
+ add_msg('foo')
839
+ assert_msg_uid(1, 2, 3, 4)
840
+
841
+ set_msg_flag(1, 'answered', true)
842
+ set_msg_flag(2, 'answered', true)
843
+ set_msg_flag(1, 'flagged', true)
844
+ set_msg_flag(3, 'flagged', true)
845
+ assert_msg_flag('answered', true, true, false, false)
846
+ assert_msg_flag('flagged', true, false, true, false)
847
+ }
848
+
849
+ parse_search_key([ 'ANSWERED', 'FLAGGED' ]) {
850
+ assert_search_cond(0, true)
851
+ assert_search_cond(1, false)
852
+ assert_search_cond(2, false)
853
+ assert_search_cond(3, false)
854
+ }
855
+
856
+ parse_search_key([ [ :group, 'ANSWERED', 'FLAGGED' ] ]) {
857
+ assert_search_cond(0, true)
858
+ assert_search_cond(1, false)
859
+ assert_search_cond(2, false)
860
+ assert_search_cond(3, false)
861
+ }
862
+
863
+ assert_search_syntax_error([ [ :block, 'ANSWERED', 'FLAGGED' ] ])
864
+ end
865
+
866
+ def test_parse_charset_body
867
+ make_search_parser(charset: 'utf-8') {
868
+ add_msg("Content-Type: text/plain\r\n" +
869
+ "\r\n" +
870
+ "foo")
871
+ add_msg("Content-Type: text/plain; charset=utf-8\r\n" +
872
+ "\r\n" +
873
+ "foo")
874
+ add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
875
+ "\r\n" +
876
+ "foo")
877
+ add_msg("Content-Type: text/plain; charset=utf-8\r\n" +
878
+ "\r\n" +
879
+ "\u3053\u3093\u306B\u3061\u306F\r\n" +
880
+ "\u3044\u308D\u306F\u306B\u307B\u3078\u3068\r\n" +
881
+ "\u3042\u3044\u3046\u3048\u304A\r\n")
882
+ add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
883
+ "\r\n" +
884
+ "\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")
885
+ assert_msg_uid(1, 2, 3, 4, 5)
886
+ }
887
+
888
+ parse_search_key([ 'BODY', 'foo' ]) {
889
+ assert_search_cond(0, true)
890
+ assert_search_cond(1, true)
891
+ assert_search_cond(2, true)
892
+ assert_search_cond(3, false)
893
+ assert_search_cond(4, false)
894
+ }
895
+
896
+ parse_search_key([ 'BODY', 'bar' ]) {
897
+ assert_search_cond(0, false)
898
+ assert_search_cond(1, false)
899
+ assert_search_cond(2, false)
900
+ assert_search_cond(3, false)
901
+ assert_search_cond(4, false)
902
+ }
903
+
904
+ parse_search_key([ 'BODY', "\u306F\u306B\u307B".b ]) {
905
+ assert_search_cond(0, false)
906
+ assert_search_cond(1, false)
907
+ assert_search_cond(2, false)
908
+ assert_search_cond(3, true)
909
+ assert_search_cond(4, true)
910
+ }
911
+ end
912
+
913
+ def test_parse_charset_text
914
+ make_search_parser(charset: 'utf-8') {
915
+ add_msg("Content-Type: text/plain\r\n" +
916
+ "foo")
917
+ add_msg("Content-Type: text/plain; charset=utf-8\r\n" +
918
+ "X-foo: dummy\r\n" +
919
+ "\r\n" +
920
+ "bar")
921
+ add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
922
+ "X-dummy: foo\r\n" +
923
+ "\r\n" +
924
+ "bar")
925
+ add_msg("Content-Type: text/plain; charset=utf-8\r\n" +
926
+ "\r\n" +
927
+ "\u3053\u3093\u306B\u3061\u306F\r\n" +
928
+ "\u3044\u308D\u306F\u306B\u307B\u3078\u3068\r\n" +
929
+ "\u3042\u3044\u3046\u3048\u304A\r\n")
930
+ add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
931
+ "\r\n" +
932
+ "\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")
933
+ assert_msg_uid(1, 2, 3, 4, 5)
934
+ }
935
+
936
+ parse_search_key([ 'TEXT', 'foo' ]) {
937
+ assert_search_cond(0, true)
938
+ assert_search_cond(1, true)
939
+ assert_search_cond(2, true)
940
+ assert_search_cond(3, false)
941
+ assert_search_cond(4, false)
942
+ }
943
+
944
+ parse_search_key([ 'TEXT', 'bar' ]) {
945
+ assert_search_cond(0, false)
946
+ assert_search_cond(1, true)
947
+ assert_search_cond(2, true)
948
+ assert_search_cond(3, false)
949
+ assert_search_cond(4, false)
950
+ }
951
+
952
+ parse_search_key([ 'TEXT', 'baz' ]) {
953
+ assert_search_cond(0, false)
954
+ assert_search_cond(1, false)
955
+ assert_search_cond(2, false)
956
+ assert_search_cond(3, false)
957
+ assert_search_cond(4, false)
958
+ }
959
+
960
+ parse_search_key([ 'TEXT', "\u306F\u306B\u307B".b ]) {
961
+ assert_search_cond(0, false)
962
+ assert_search_cond(1, false)
963
+ assert_search_cond(2, false)
964
+ assert_search_cond(3, true)
965
+ assert_search_cond(4, true)
966
+ }
967
+ end
968
+ end
969
+ end
970
+
971
+ # Local Variables:
972
+ # mode: Ruby
973
+ # indent-tabs-mode: nil
974
+ # End: