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,696 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'pp' if $DEBUG
4
+ require 'rims'
5
+ require 'test/unit'
6
+
7
+ module RIMS::Test
8
+ class RFC822ParserTest < Test::Unit::TestCase
9
+ include AssertUtility
10
+
11
+ def test_split_message
12
+ msg =
13
+ "Content-Type: text/plain\r\n" +
14
+ "Subject: test\r\n" +
15
+ "\r\n" +
16
+ "HALO\r\n"
17
+ header_body_pair = RIMS::RFC822.split_message(msg.b)
18
+ assert_strenc_equal('ascii-8bit',
19
+ "Content-Type: text/plain\r\n" +
20
+ "Subject: test\r\n" +
21
+ "\r\n",
22
+ header_body_pair[0])
23
+ assert_strenc_equal('ascii-8bit',
24
+ "HALO\r\n",
25
+ header_body_pair[1])
26
+
27
+ msg =
28
+ "Content-Type: text/plain\n" +
29
+ "Subject: test\n" +
30
+ "\n" +
31
+ "HALO\n"
32
+ header_body_pair = RIMS::RFC822.split_message(msg.b)
33
+ assert_strenc_equal('ascii-8bit',
34
+ "Content-Type: text/plain\n" +
35
+ "Subject: test\n" +
36
+ "\n",
37
+ header_body_pair[0])
38
+ assert_strenc_equal('ascii-8bit',
39
+ "HALO\n",
40
+ header_body_pair[1])
41
+
42
+ msg =
43
+ "\n" +
44
+ "\r\n" +
45
+ " \t\n" +
46
+ "Content-Type: text/plain\r\n" +
47
+ "Subject: test\r\n" +
48
+ "\r\n" +
49
+ "HALO\r\n"
50
+ header_body_pair = RIMS::RFC822.split_message(msg.b)
51
+ assert_strenc_equal('ascii-8bit',
52
+ "Content-Type: text/plain\r\n" +
53
+ "Subject: test\r\n" +
54
+ "\r\n",
55
+ header_body_pair[0])
56
+ assert_strenc_equal('ascii-8bit',
57
+ "HALO\r\n",
58
+ header_body_pair[1])
59
+
60
+ msg =
61
+ "Content-Type: text/plain\r\n" +
62
+ "Subject: test\r\n" +
63
+ "\r\n"
64
+ header_body_pair = RIMS::RFC822.split_message(msg.b)
65
+ assert_strenc_equal('ascii-8bit',
66
+ "Content-Type: text/plain\r\n" +
67
+ "Subject: test\r\n" +
68
+ "\r\n",
69
+ header_body_pair[0])
70
+ assert_strenc_equal('ascii-8bit', '', header_body_pair[1])
71
+
72
+ msg =
73
+ "Content-Type: text/plain\r\n" +
74
+ "Subject: test\r\n"
75
+ header_body_pair = RIMS::RFC822.split_message(msg.b)
76
+ assert_strenc_equal('ascii-8bit',
77
+ "Content-Type: text/plain\r\n" +
78
+ "Subject: test\r\n",
79
+ header_body_pair[0])
80
+ assert_nil(header_body_pair[1])
81
+ end
82
+
83
+ def test_parse_header
84
+ assert_equal([], RIMS::RFC822.parse_header(''.b))
85
+
86
+ field_pair_list = RIMS::RFC822.parse_header("Content-Type: text/plain; charset=utf-8\r\n".b +
87
+ "Subject: This is a test\r\n".b +
88
+ "\r\n".b)
89
+ assert_equal(2, field_pair_list.length)
90
+ assert_strenc_equal('ascii-8bit', 'Content-Type', field_pair_list[0][0])
91
+ assert_strenc_equal('ascii-8bit', 'text/plain; charset=utf-8', field_pair_list[0][1])
92
+ assert_strenc_equal('ascii-8bit', 'Subject', field_pair_list[1][0])
93
+ assert_strenc_equal('ascii-8bit', 'This is a test', field_pair_list[1][1])
94
+
95
+ field_pair_list = RIMS::RFC822.parse_header("Content-Type: text/plain; charset=utf-8\r\n".b +
96
+ "Subject: This is a test\r\n".b)
97
+ assert_equal(2, field_pair_list.length)
98
+ assert_strenc_equal('ascii-8bit', 'Content-Type', field_pair_list[0][0])
99
+ assert_strenc_equal('ascii-8bit', 'text/plain; charset=utf-8', field_pair_list[0][1])
100
+ assert_strenc_equal('ascii-8bit', 'Subject', field_pair_list[1][0])
101
+ assert_strenc_equal('ascii-8bit', 'This is a test', field_pair_list[1][1])
102
+
103
+ field_pair_list = RIMS::RFC822.parse_header("Content-Type: text/plain; charset=utf-8\r\n".b +
104
+ "Subject: This is a test".b)
105
+ assert_equal(2, field_pair_list.length)
106
+ assert_strenc_equal('ascii-8bit', 'Content-Type', field_pair_list[0][0])
107
+ assert_strenc_equal('ascii-8bit', 'text/plain; charset=utf-8', field_pair_list[0][1])
108
+ assert_strenc_equal('ascii-8bit', 'Subject', field_pair_list[1][0])
109
+ assert_strenc_equal('ascii-8bit', 'This is a test', field_pair_list[1][1])
110
+
111
+ field_pair_list = RIMS::RFC822.parse_header("Content-Type:\r\n".b +
112
+ " text/plain;\r\n".b +
113
+ " charset=utf-8\r\n".b +
114
+ "Subject: This\n".b +
115
+ " is a test\r\n".b +
116
+ "\r\n".b)
117
+ assert_equal(2, field_pair_list.length)
118
+ assert_strenc_equal('ascii-8bit', 'Content-Type', field_pair_list[0][0])
119
+ assert_strenc_equal('ascii-8bit', "text/plain;\r\n charset=utf-8", field_pair_list[0][1])
120
+ assert_strenc_equal('ascii-8bit', 'Subject', field_pair_list[1][0])
121
+ assert_strenc_equal('ascii-8bit', "This\n is a test", field_pair_list[1][1])
122
+
123
+ field_pair_list = RIMS::RFC822.parse_header('foo'.b)
124
+ assert_equal(0, field_pair_list.length)
125
+
126
+ field_pair_list = RIMS::RFC822.parse_header('foo:bar:baz'.b)
127
+ assert_equal(1, field_pair_list.length)
128
+ assert_strenc_equal('ascii-8bit', 'foo', field_pair_list[0][0])
129
+ assert_strenc_equal('ascii-8bit', 'bar:baz', field_pair_list[0][1])
130
+ end
131
+
132
+ def test_parse_content_type
133
+ content_type = RIMS::RFC822.parse_content_type('text/plain'.b)
134
+ assert_equal([ 'text', 'plain', {} ], content_type)
135
+ assert(content_type[0..1].all?{|s| s.encoding == Encoding::ASCII_8BIT })
136
+
137
+ content_type = RIMS::RFC822.parse_content_type('text/plain; charset=utf-8'.b)
138
+ assert_equal([ 'text', 'plain', { 'charset' => %w[ charset utf-8 ] } ], content_type)
139
+ assert(content_type[0..1].all?{|s| s.encoding == Encoding::ASCII_8BIT })
140
+ assert(content_type[2].each_pair.to_a.flatten.all?{|s| s.encoding == Encoding::ASCII_8BIT })
141
+
142
+ content_type = RIMS::RFC822.parse_content_type('text/plain; CHARSET=UTF-8; Foo=apple; Bar="banana"'.b)
143
+ assert_equal([ 'text', 'plain',
144
+ { 'charset' => %w[ CHARSET UTF-8 ],
145
+ 'foo' => %w[ Foo apple ],
146
+ 'bar' => %w[ Bar banana ]
147
+ }
148
+ ], content_type)
149
+ assert(content_type[0..1].all?{|s| s.encoding == Encoding::ASCII_8BIT })
150
+ assert(content_type[2].each_pair.to_a.flatten.all?{|s| s.encoding == Encoding::ASCII_8BIT })
151
+
152
+ content_type = RIMS::RFC822.parse_content_type('text/plain;CHARSET=UTF-8;Foo=apple;Bar="banana"'.b)
153
+ assert_equal([ 'text', 'plain',
154
+ { 'charset' => %w[ CHARSET UTF-8 ],
155
+ 'foo' => %w[ Foo apple ],
156
+ 'bar' => %w[ Bar banana ]
157
+ }
158
+ ], content_type)
159
+ assert(content_type[0..1].all?{|s| s.encoding == Encoding::ASCII_8BIT })
160
+ assert(content_type[2].each_pair.to_a.flatten.all?{|s| s.encoding == Encoding::ASCII_8BIT })
161
+
162
+ content_type = RIMS::RFC822.parse_content_type('multipart/mixed; boundary=----=_Part_1459890_1462677911.1383882437398'.b)
163
+ assert_equal([ 'multipart', 'mixed',
164
+ { 'boundary' => %w[ boundary ----=_Part_1459890_1462677911.1383882437398 ] }
165
+ ], content_type)
166
+ assert(content_type[0..1].all?{|s| s.encoding == Encoding::ASCII_8BIT })
167
+ assert(content_type[2].each_pair.to_a.flatten.all?{|s| s.encoding == Encoding::ASCII_8BIT })
168
+
169
+ content_type = RIMS::RFC822.parse_content_type("multipart/alternative; \r\n boundary=\"----=_Part_1459891_982342968.1383882437398\"".b)
170
+ assert_equal([ 'multipart', 'alternative',
171
+ { 'boundary' => %w[ boundary ----=_Part_1459891_982342968.1383882437398 ] }
172
+ ], content_type)
173
+ assert(content_type[0..1].all?{|s| s.encoding == Encoding::ASCII_8BIT })
174
+ assert(content_type[2].each_pair.to_a.flatten.all?{|s| s.encoding == Encoding::ASCII_8BIT })
175
+
176
+ assert_equal([ 'application', 'octet-stream', {} ], RIMS::RFC822.parse_content_type(''))
177
+ end
178
+
179
+ def test_parse_multipart_body
180
+ body_txt = <<-'MULTIPART'.b
181
+ ------=_Part_1459890_1462677911.1383882437398
182
+ Content-Type: multipart/alternative;
183
+ boundary="----=_Part_1459891_982342968.1383882437398"
184
+
185
+ ------=_Part_1459891_982342968.1383882437398
186
+ Content-Type: text/plain; charset=UTF-8
187
+ Content-Transfer-Encoding: base64
188
+
189
+ Cgo9PT09PT09PT09CkFNQVpPTi5DTy5KUAo9PT09PT09PT09CkFtYXpvbi5jby5qcOOBp+WVhuWT
190
+ rpvjgavpgIHkv6HjgZXjgozjgb7jgZfjgZ86IHRva2lAZnJlZWRvbS5uZS5qcAoKCg==
191
+ ------=_Part_1459891_982342968.1383882437398
192
+ Content-Type: text/html; charset=UTF-8
193
+ Content-Transfer-Encoding: quoted-printable
194
+
195
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
196
+
197
+ ------=_Part_1459891_982342968.1383882437398--
198
+
199
+ ------=_Part_1459890_1462677911.1383882437398--
200
+ MULTIPART
201
+
202
+ part_list = RIMS::RFC822.parse_multipart_body('----=_Part_1459890_1462677911.1383882437398'.b, body_txt)
203
+ assert_equal(1, part_list.length)
204
+ assert_strenc_equal('ascii-8bit', <<-'PART', part_list[0])
205
+ Content-Type: multipart/alternative;
206
+ boundary="----=_Part_1459891_982342968.1383882437398"
207
+
208
+ ------=_Part_1459891_982342968.1383882437398
209
+ Content-Type: text/plain; charset=UTF-8
210
+ Content-Transfer-Encoding: base64
211
+
212
+ Cgo9PT09PT09PT09CkFNQVpPTi5DTy5KUAo9PT09PT09PT09CkFtYXpvbi5jby5qcOOBp+WVhuWT
213
+ rpvjgavpgIHkv6HjgZXjgozjgb7jgZfjgZ86IHRva2lAZnJlZWRvbS5uZS5qcAoKCg==
214
+ ------=_Part_1459891_982342968.1383882437398
215
+ Content-Type: text/html; charset=UTF-8
216
+ Content-Transfer-Encoding: quoted-printable
217
+
218
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
219
+
220
+ ------=_Part_1459891_982342968.1383882437398--
221
+ PART
222
+
223
+ header_txt, body_txt = RIMS::RFC822.split_message(part_list[0])
224
+ content_type_txt = RIMS::RFC822.parse_header(header_txt).find{|n, v| n == 'Content-Type' }[1]
225
+ boundary = RIMS::RFC822.parse_content_type(content_type_txt)[2]['boundary'][1]
226
+
227
+ part_list = RIMS::RFC822.parse_multipart_body(boundary, body_txt)
228
+ assert_equal(2, part_list.length)
229
+ assert_strenc_equal('ascii-8bit', <<-'PART1'.chomp, part_list[0])
230
+ Content-Type: text/plain; charset=UTF-8
231
+ Content-Transfer-Encoding: base64
232
+
233
+ Cgo9PT09PT09PT09CkFNQVpPTi5DTy5KUAo9PT09PT09PT09CkFtYXpvbi5jby5qcOOBp+WVhuWT
234
+ rpvjgavpgIHkv6HjgZXjgozjgb7jgZfjgZ86IHRva2lAZnJlZWRvbS5uZS5qcAoKCg==
235
+ PART1
236
+ assert_strenc_equal('ascii-8bit', <<-'PART2', part_list[1])
237
+ Content-Type: text/html; charset=UTF-8
238
+ Content-Transfer-Encoding: quoted-printable
239
+
240
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
241
+ PART2
242
+ end
243
+
244
+ def test_parse_multipart_body_bad_format
245
+ assert_equal(%w[ foo bar baz ], RIMS::RFC822.parse_multipart_body('sep', <<-EOF))
246
+ --sep
247
+ foo
248
+ --sep
249
+ bar
250
+ --sep
251
+ baz
252
+ EOF
253
+
254
+ assert_equal([], RIMS::RFC822.parse_multipart_body('sep', <<-EOF))
255
+ --sep--
256
+ EOF
257
+
258
+ assert_equal([], RIMS::RFC822.parse_multipart_body('sep', 'detarame'))
259
+ assert_equal([], RIMS::RFC822.parse_multipart_body('sep', ''))
260
+ end
261
+
262
+ def test_unquote_phrase_raw
263
+ assert_strenc_equal('ascii-8bit', '', RIMS::RFC822.unquote_phrase(''.b))
264
+ assert_strenc_equal('ascii-8bit', 'Hello world.', RIMS::RFC822.unquote_phrase('Hello world.'.b))
265
+ assert_strenc_equal('ascii-8bit', "\" ( ) \\", RIMS::RFC822.unquote_phrase("\\\" \\( \\) \\\\".b))
266
+ end
267
+
268
+ def test_unquote_phrase_quote
269
+ assert_strenc_equal('ascii-8bit', '', RIMS::RFC822.unquote_phrase('""'.b))
270
+ assert_strenc_equal('ascii-8bit', 'Hello world.', RIMS::RFC822.unquote_phrase('"Hello world."'.b))
271
+ assert_strenc_equal('ascii-8bit', 'foo "bar" baz', RIMS::RFC822.unquote_phrase("\"foo \\\"bar\\\" baz\"".b))
272
+ assert_strenc_equal('ascii-8bit', 'foo (bar) baz', RIMS::RFC822.unquote_phrase('"foo (bar) baz"'.b))
273
+ end
274
+
275
+ def test_unquote_phrase_comment
276
+ assert_strenc_equal('ascii-8bit', '', RIMS::RFC822.unquote_phrase('()'.b))
277
+ assert_strenc_equal('ascii-8bit', '', RIMS::RFC822.unquote_phrase('(Hello world.)'.b))
278
+ assert_strenc_equal('ascii-8bit', '', RIMS::RFC822.unquote_phrase("( \" \\( \\) \\\\ )".b))
279
+ end
280
+
281
+ def test_unquote_phrase_abnormal_patterns
282
+ assert_strenc_equal('ascii-8bit', '', RIMS::RFC822.unquote_phrase("\\".b))
283
+ assert_strenc_equal('ascii-8bit', 'foo', RIMS::RFC822.unquote_phrase('"foo'.b))
284
+ assert_strenc_equal('ascii-8bit', 'foo', RIMS::RFC822.unquote_phrase(%Q'"foo\\'.b))
285
+ assert_strenc_equal('ascii-8bit', '', RIMS::RFC822.unquote_phrase('(foo'.b))
286
+ assert_strenc_equal('ascii-8bit', '', RIMS::RFC822.unquote_phrase("(foo\\".b))
287
+ end
288
+
289
+ def test_parse_mail_address_list_addr_spec
290
+ assert_equal([], RIMS::RFC822.parse_mail_address_list(''.b))
291
+ assert_equal([ [ nil, nil, 'toki', 'freedom.ne.jp' ] ],
292
+ RIMS::RFC822.parse_mail_address_list('toki@freedom.ne.jp'.b))
293
+ assert_equal([ [ nil, nil, 'toki', 'freedom.ne.jp' ] ],
294
+ RIMS::RFC822.parse_mail_address_list(' toki@freedom.ne.jp '.b))
295
+ end
296
+
297
+ def test_parse_mail_address_list_name_addr
298
+ assert_equal([ [ 'TOKI Yoshinori', nil, 'toki', 'freedom.ne.jp' ] ],
299
+ RIMS::RFC822.parse_mail_address_list('TOKI Yoshinori <toki@freedom.ne.jp>'.b))
300
+ assert_equal([ [ 'TOKI Yoshinori', nil, 'toki', 'freedom.ne.jp' ] ],
301
+ RIMS::RFC822.parse_mail_address_list('"TOKI Yoshinori" <toki@freedom.ne.jp>'.b))
302
+ assert_equal([ [ 'TOKI Yoshinori', nil, 'toki', 'freedom.ne.jp' ] ],
303
+ RIMS::RFC822.parse_mail_address_list('TOKI(土岐) Yoshinori <toki@freedom.ne.jp>'.b))
304
+ assert_equal([ [ 'TOKI,Yoshinori', nil, 'toki', 'freedom.ne.jp' ] ],
305
+ RIMS::RFC822.parse_mail_address_list('TOKI\,Yoshinori <toki@freedom.ne.jp>'.b))
306
+ assert_equal([ [ 'toki@freedom.ne.jp', nil, 'toki', 'freedom.ne.jp' ] ],
307
+ RIMS::RFC822.parse_mail_address_list('"toki@freedom.ne.jp" <toki@freedom.ne.jp>'.b))
308
+ end
309
+
310
+ def test_parse_mail_address_list_route_addr
311
+ assert_equal([ [ 'TOKI Yoshinori', '@mail.freedom.ne.jp,@smtp.gmail.com', 'toki', 'freedom.ne.jp' ] ],
312
+ RIMS::RFC822.parse_mail_address_list('TOKI Yoshinori <@mail.freedom.ne.jp,@smtp.gmail.com:toki@freedom.ne.jp>'.b))
313
+ end
314
+
315
+ def test_parse_mail_address_list_group
316
+ assert_equal([ [ nil, nil, 'toki', nil ],
317
+ [ nil, nil, 'toki', 'freedom.ne.jp' ],
318
+ [ 'TOKI Yoshinori', nil, 'toki', 'freedom.ne.jp' ],
319
+ [ 'TOKI Yoshinori', '@mail.freedom.ne.jp,@smtp.gmail.com', 'toki', 'freedom.ne.jp' ],
320
+ [ nil, nil, nil, nil ]
321
+ ],
322
+ RIMS::RFC822.parse_mail_address_list('toki: ' +
323
+ 'toki@freedom.ne.jp, ' +
324
+ 'TOKI Yoshinori <toki@freedom.ne.jp>, ' +
325
+ 'TOKI Yoshinori <@mail.freedom.ne.jp,@smtp.gmail.com:toki@freedom.ne.jp>' +
326
+ ';'.b))
327
+ end
328
+
329
+ def test_parse_mail_address_list_multiline
330
+ assert_equal([ [ nil, nil, 'toki', 'freedom.ne.jp' ],
331
+ [ 'TOKI Yoshinori', nil, 'toki', 'freedom.ne.jp' ],
332
+ [ 'Yoshinori Toki', nil, 'toki', 'freedom.ne.jp' ]
333
+ ],
334
+ RIMS::RFC822.parse_mail_address_list("toki@freedom.ne.jp,\n" +
335
+ " TOKI Yoshinori <toki@freedom.ne.jp>\n" +
336
+ " , Yoshinori Toki <toki@freedom.ne.jp> "))
337
+ end
338
+ end
339
+
340
+ class RFC822HeaderText < Test::Unit::TestCase
341
+ def setup
342
+ @header = RIMS::RFC822::Header.new("foo: apple\r\n" +
343
+ "bar: Bob\r\n" +
344
+ "Foo: banana\r\n" +
345
+ "FOO: orange\r\n" +
346
+ "\r\n")
347
+ pp @header if $DEBUG
348
+ end
349
+
350
+ def teardown
351
+ pp @header if $DEBUG
352
+ end
353
+
354
+ def test_each
355
+ assert_equal([ %w[ foo apple ], %w[ bar Bob ], %w[ Foo banana ], %w[ FOO orange ] ],
356
+ @header.each.to_a)
357
+ end
358
+
359
+ def test_key?
360
+ assert_equal(true, (@header.key? 'foo'))
361
+ assert_equal(true, (@header.key? 'Foo'))
362
+ assert_equal(true, (@header.key? 'FOO'))
363
+
364
+ assert_equal(true, (@header.key? 'bar'))
365
+ assert_equal(true, (@header.key? 'Bar'))
366
+ assert_equal(true, (@header.key? 'BAR'))
367
+
368
+ assert_equal(false, (@header.key? 'baz'))
369
+ assert_equal(false, (@header.key? 'Baz'))
370
+ assert_equal(false, (@header.key? 'BAZ'))
371
+ end
372
+
373
+ def test_fetch
374
+ assert_equal('apple', @header['foo'])
375
+ assert_equal('apple', @header['Foo'])
376
+ assert_equal('apple', @header['FOO'])
377
+
378
+ assert_equal('Bob', @header['bar'])
379
+ assert_equal('Bob', @header['Bar'])
380
+ assert_equal('Bob', @header['BAR'])
381
+
382
+ assert_nil(@header['baz'])
383
+ assert_nil(@header['Baz'])
384
+ assert_nil(@header['BAZ'])
385
+ end
386
+
387
+ def test_fetch_upcase
388
+ assert_equal('APPLE', @header.fetch_upcase('foo'))
389
+ assert_equal('APPLE', @header.fetch_upcase('Foo'))
390
+ assert_equal('APPLE', @header.fetch_upcase('FOO'))
391
+
392
+ assert_equal('BOB', @header.fetch_upcase('bar'))
393
+ assert_equal('BOB', @header.fetch_upcase('Bar'))
394
+ assert_equal('BOB', @header.fetch_upcase('BAR'))
395
+
396
+ assert_nil(@header.fetch_upcase('baz'))
397
+ assert_nil(@header.fetch_upcase('Baz'))
398
+ assert_nil(@header.fetch_upcase('BAZ'))
399
+ end
400
+
401
+ def test_field_value_list
402
+ assert_equal(%w[ apple banana orange ], @header.field_value_list('foo'))
403
+ assert_equal(%w[ apple banana orange ], @header.field_value_list('Foo'))
404
+ assert_equal(%w[ apple banana orange ], @header.field_value_list('FOO'))
405
+
406
+ assert_equal(%w[ Bob ], @header.field_value_list('bar'))
407
+ assert_equal(%w[ Bob ], @header.field_value_list('Bar'))
408
+ assert_equal(%w[ Bob ], @header.field_value_list('BAR'))
409
+
410
+ assert_nil(@header.field_value_list('baz'))
411
+ assert_nil(@header.field_value_list('Baz'))
412
+ assert_nil(@header.field_value_list('BAZ'))
413
+ end
414
+ end
415
+
416
+ class RFC822MessageTest < Test::Unit::TestCase
417
+ def setup_message(headers={},
418
+ content_type: 'text/plain; charset=utf-8',
419
+ body: "Hello world.\r\n")
420
+ @msg = RIMS::RFC822::Message.new(headers.map{|n, v| "#{n}: #{v}\r\n" }.join('') +
421
+ "Content-Type: #{content_type}\r\n" +
422
+ "Subject: test\r\n" +
423
+ "\r\n" +
424
+ body)
425
+ pp @msg if $DEBUG
426
+ end
427
+
428
+ def teardown
429
+ pp @msg if $DEBUG
430
+ end
431
+
432
+ def test_header
433
+ setup_message
434
+ assert_equal("Content-Type: text/plain; charset=utf-8\r\n" +
435
+ "Subject: test\r\n" +
436
+ "\r\n",
437
+ @msg.header.raw_source)
438
+ end
439
+
440
+ def test_body
441
+ setup_message
442
+ assert_equal("Hello world.\r\n", @msg.body.raw_source)
443
+ end
444
+
445
+ def test_media_main_type
446
+ setup_message
447
+ assert_equal('text', @msg.media_main_type)
448
+ assert_equal('TEXT', @msg.media_main_type_upcase)
449
+ end
450
+
451
+ def test_media_sub_type
452
+ setup_message
453
+ assert_equal('plain', @msg.media_sub_type)
454
+ assert_equal('PLAIN', @msg.media_sub_type_upcase)
455
+ end
456
+
457
+ def test_content_type
458
+ setup_message
459
+ assert_equal('text/plain', @msg.content_type)
460
+ assert_equal('TEXT/PLAIN', @msg.content_type_upcase)
461
+ end
462
+
463
+ def test_content_type_parameters
464
+ setup_message(content_type: 'text/plain; charset=utf-8; foo=apple; Bar=Banana')
465
+ assert_equal([ %w[ charset utf-8 ], %w[ foo apple ], %w[ Bar Banana ] ], @msg.content_type_parameters)
466
+ end
467
+
468
+ def test_charset
469
+ setup_message
470
+ assert_equal('utf-8', @msg.charset)
471
+ end
472
+
473
+ def test_charset_no_value
474
+ setup_message(content_type: 'text/plain')
475
+ assert_nil(@msg.charset)
476
+ end
477
+
478
+ def test_boundary
479
+ setup_message(content_type: "multipart/alternative; \r\n boundary=\"----=_Part_1459891_982342968.1383882437398\"")
480
+ assert_equal('----=_Part_1459891_982342968.1383882437398', @msg.boundary)
481
+ end
482
+
483
+ def test_boundary_no_value
484
+ setup_message
485
+ assert_nil(@msg.boundary)
486
+ end
487
+
488
+ def test_text?
489
+ setup_message
490
+ assert_equal(true, @msg.text?)
491
+ end
492
+
493
+ def test_not_text?
494
+ setup_message(content_type: 'application/octet-stream')
495
+ assert_equal(false, @msg.text?)
496
+ end
497
+
498
+ def test_multipart?
499
+ setup_message(content_type: 'multipart/mixed')
500
+ assert_equal(true, @msg.multipart?)
501
+ end
502
+
503
+ def test_not_multipart?
504
+ setup_message
505
+ assert_equal(false, @msg.multipart?)
506
+ end
507
+
508
+ def test_parts
509
+ setup_message(content_type: 'multipart/mixed; boundary="----=_Part_1459890_1462677911.1383882437398"', body: <<-'EOF')
510
+ ------=_Part_1459890_1462677911.1383882437398
511
+ Content-Type: multipart/alternative;
512
+ boundary="----=_Part_1459891_982342968.1383882437398"
513
+
514
+ ------=_Part_1459891_982342968.1383882437398
515
+ Content-Type: text/plain; charset=UTF-8
516
+ Content-Transfer-Encoding: base64
517
+
518
+ Cgo9PT09PT09PT09CkFNQVpPTi5DTy5KUAo9PT09PT09PT09CkFtYXpvbi5jby5qcOOBp+WVhuWT
519
+ rpvjgavpgIHkv6HjgZXjgozjgb7jgZfjgZ86IHRva2lAZnJlZWRvbS5uZS5qcAoKCg==
520
+ ------=_Part_1459891_982342968.1383882437398
521
+ Content-Type: text/html; charset=UTF-8
522
+ Content-Transfer-Encoding: quoted-printable
523
+
524
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
525
+
526
+ ------=_Part_1459891_982342968.1383882437398--
527
+
528
+ ------=_Part_1459890_1462677911.1383882437398--
529
+ EOF
530
+
531
+ assert_equal(1, @msg.parts.length)
532
+ assert_equal(<<-'EOF', @msg.parts[0].raw_source)
533
+ Content-Type: multipart/alternative;
534
+ boundary="----=_Part_1459891_982342968.1383882437398"
535
+
536
+ ------=_Part_1459891_982342968.1383882437398
537
+ Content-Type: text/plain; charset=UTF-8
538
+ Content-Transfer-Encoding: base64
539
+
540
+ Cgo9PT09PT09PT09CkFNQVpPTi5DTy5KUAo9PT09PT09PT09CkFtYXpvbi5jby5qcOOBp+WVhuWT
541
+ rpvjgavpgIHkv6HjgZXjgozjgb7jgZfjgZ86IHRva2lAZnJlZWRvbS5uZS5qcAoKCg==
542
+ ------=_Part_1459891_982342968.1383882437398
543
+ Content-Type: text/html; charset=UTF-8
544
+ Content-Transfer-Encoding: quoted-printable
545
+
546
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
547
+
548
+ ------=_Part_1459891_982342968.1383882437398--
549
+ EOF
550
+
551
+ assert_equal(2, @msg.parts[0].parts.length)
552
+ assert_equal(<<-'EOF'.chomp, @msg.parts[0].parts[0].raw_source)
553
+ Content-Type: text/plain; charset=UTF-8
554
+ Content-Transfer-Encoding: base64
555
+
556
+ Cgo9PT09PT09PT09CkFNQVpPTi5DTy5KUAo9PT09PT09PT09CkFtYXpvbi5jby5qcOOBp+WVhuWT
557
+ rpvjgavpgIHkv6HjgZXjgozjgb7jgZfjgZ86IHRva2lAZnJlZWRvbS5uZS5qcAoKCg==
558
+ EOF
559
+ assert_equal(<<-'EOF', @msg.parts[0].parts[1].raw_source)
560
+ Content-Type: text/html; charset=UTF-8
561
+ Content-Transfer-Encoding: quoted-printable
562
+
563
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
564
+ EOF
565
+ end
566
+
567
+ def test_parts_not_multipart
568
+ setup_message
569
+ assert_nil(@msg.parts)
570
+ end
571
+
572
+ def test_parts_no_boundary
573
+ setup_message(content_type: 'multipart/mixed')
574
+ assert_equal([], @msg.parts)
575
+ end
576
+
577
+ def test_message?
578
+ setup_message(content_type: 'message/rfc822')
579
+ assert_equal(true, @msg.message?)
580
+ end
581
+
582
+ def test_not_message?
583
+ setup_message
584
+ assert_equal(false, @msg.message?)
585
+ end
586
+
587
+ def test_message
588
+ setup_message(content_type: 'message/rfc822', body: <<-'EOF')
589
+ To: bar@nonet.com
590
+ From: foo@nonet.com
591
+ Subject: inner multipart
592
+ MIME-Version: 1.0
593
+ Date: Fri, 8 Nov 2013 19:31:03 +0900
594
+ Content-Type: multipart/mixed; boundary="1383.905529.351298"
595
+
596
+ --1383.905529.351298
597
+ Content-Type: text/plain; charset=us-ascii
598
+
599
+ Hello world.
600
+ --1383.905529.351298
601
+ Content-Type: application/octet-stream
602
+
603
+ 9876543210
604
+ --1383.905529.351298--
605
+ EOF
606
+
607
+ assert_equal(<<-'EOF', @msg.message.raw_source)
608
+ To: bar@nonet.com
609
+ From: foo@nonet.com
610
+ Subject: inner multipart
611
+ MIME-Version: 1.0
612
+ Date: Fri, 8 Nov 2013 19:31:03 +0900
613
+ Content-Type: multipart/mixed; boundary="1383.905529.351298"
614
+
615
+ --1383.905529.351298
616
+ Content-Type: text/plain; charset=us-ascii
617
+
618
+ Hello world.
619
+ --1383.905529.351298
620
+ Content-Type: application/octet-stream
621
+
622
+ 9876543210
623
+ --1383.905529.351298--
624
+ EOF
625
+ assert_equal(true, @msg.message.multipart?)
626
+ assert_equal(2, @msg.message.parts.length)
627
+ assert_equal('text/plain', @msg.message.parts[0].content_type)
628
+ assert_equal('us-ascii', @msg.message.parts[0].charset)
629
+ assert_equal('Hello world.', @msg.message.parts[0].body.raw_source)
630
+ assert_equal('application/octet-stream', @msg.message.parts[1].content_type)
631
+ assert_equal('9876543210', @msg.message.parts[1].body.raw_source)
632
+ end
633
+
634
+ def test_message_no_msg
635
+ setup_message
636
+ assert_nil(@msg.message)
637
+ end
638
+
639
+ def test_date
640
+ setup_message('Date' => 'Fri, 8 Nov 2013 03:47:17 +0000')
641
+ assert_equal(Time.utc(2013, 11, 8, 3, 47, 17), @msg.date)
642
+ end
643
+
644
+ def test_date_no_value
645
+ setup_message
646
+ assert_nil(@msg.date)
647
+ end
648
+
649
+ def test_date_bad_format
650
+ setup_message('Date' => 'no_date')
651
+ assert_equal(Time.at(0), @msg.date)
652
+ end
653
+
654
+ def test_mail_address_header_field
655
+ setup_message('From' => 'Foo <foo@mail.example.com>',
656
+ 'Sender' => 'Bar <bar@mail.example.com>',
657
+ 'Reply-To' => 'Baz <baz@mail.example.com>',
658
+ 'To' => 'Alice <alice@mail.example.com>',
659
+ 'Cc' => 'Bob <bob@mail.example.com>',
660
+ 'Bcc' => 'Kate <kate@mail.example.com>')
661
+
662
+ assert_equal([ [ 'Foo', nil, 'foo', 'mail.example.com' ] ], @msg.from)
663
+ assert_equal([ [ 'Bar', nil, 'bar', 'mail.example.com' ] ], @msg.sender)
664
+ assert_equal([ [ 'Baz', nil, 'baz', 'mail.example.com' ] ], @msg.reply_to)
665
+ assert_equal([ [ 'Alice', nil, 'alice', 'mail.example.com' ] ], @msg.to)
666
+ assert_equal([ [ 'Bob', nil, 'bob', 'mail.example.com' ] ], @msg.cc)
667
+ assert_equal([ [ 'Kate', nil, 'kate', 'mail.example.com' ] ], @msg.bcc)
668
+ end
669
+
670
+ def test_mail_address_header_field_multi_header_field
671
+ setup_message([ [ 'From', 'Foo <foo@mail.example.com>, Bar <bar@mail.example.com>' ],
672
+ [ 'from', 'Baz <baz@mail.example.com>' ]
673
+ ])
674
+ assert_equal([ [ 'Foo', nil, 'foo', 'mail.example.com' ],
675
+ [ 'Bar', nil, 'bar', 'mail.example.com' ],
676
+ [ 'Baz', nil, 'baz', 'mail.example.com' ]
677
+ ],
678
+ @msg.from)
679
+ end
680
+
681
+ def test_mail_address_header_field_no_value
682
+ setup_message
683
+ assert_nil(@msg.from)
684
+ end
685
+
686
+ def test_mail_address_header_field_bad_format
687
+ setup_message('From' => 'no_mail_address')
688
+ assert_equal([], @msg.from)
689
+ end
690
+ end
691
+ end
692
+
693
+ # Local Variables:
694
+ # mode: Ruby
695
+ # indent-tabs-mode: nil
696
+ # End: