rims 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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: