rmail 0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/NEWS +309 -0
  2. data/NOTES +14 -0
  3. data/README +83 -0
  4. data/THANKS +25 -0
  5. data/TODO +112 -0
  6. data/guide/Intro.txt +122 -0
  7. data/guide/MIME.txt +6 -0
  8. data/guide/TableOfContents.txt +13 -0
  9. data/install.rb +1023 -0
  10. data/lib/rmail.rb +50 -0
  11. data/lib/rmail/address.rb +829 -0
  12. data/lib/rmail/header.rb +987 -0
  13. data/lib/rmail/mailbox.rb +62 -0
  14. data/lib/rmail/mailbox/mboxreader.rb +182 -0
  15. data/lib/rmail/message.rb +201 -0
  16. data/lib/rmail/parser.rb +412 -0
  17. data/lib/rmail/parser/multipart.rb +217 -0
  18. data/lib/rmail/parser/pushbackreader.rb +173 -0
  19. data/lib/rmail/serialize.rb +190 -0
  20. data/lib/rmail/utils.rb +59 -0
  21. data/rmail.gemspec +17 -0
  22. data/tests/addrgrammar.txt +113 -0
  23. data/tests/data/mbox.odd +4 -0
  24. data/tests/data/mbox.simple +8 -0
  25. data/tests/data/multipart/data.1 +5 -0
  26. data/tests/data/multipart/data.10 +1 -0
  27. data/tests/data/multipart/data.11 +9 -0
  28. data/tests/data/multipart/data.12 +9 -0
  29. data/tests/data/multipart/data.13 +3 -0
  30. data/tests/data/multipart/data.14 +3 -0
  31. data/tests/data/multipart/data.15 +3 -0
  32. data/tests/data/multipart/data.16 +3 -0
  33. data/tests/data/multipart/data.17 +0 -0
  34. data/tests/data/multipart/data.2 +5 -0
  35. data/tests/data/multipart/data.3 +2 -0
  36. data/tests/data/multipart/data.4 +3 -0
  37. data/tests/data/multipart/data.5 +1 -0
  38. data/tests/data/multipart/data.6 +2 -0
  39. data/tests/data/multipart/data.7 +3 -0
  40. data/tests/data/multipart/data.8 +5 -0
  41. data/tests/data/multipart/data.9 +4 -0
  42. data/tests/data/parser.badmime1 +4 -0
  43. data/tests/data/parser.badmime2 +6 -0
  44. data/tests/data/parser.nested-multipart +75 -0
  45. data/tests/data/parser.nested-simple +12 -0
  46. data/tests/data/parser.nested-simple2 +16 -0
  47. data/tests/data/parser.nested-simple3 +21 -0
  48. data/tests/data/parser.rfc822 +65 -0
  49. data/tests/data/parser.simple-mime +24 -0
  50. data/tests/data/parser/multipart.1 +8 -0
  51. data/tests/data/parser/multipart.10 +4 -0
  52. data/tests/data/parser/multipart.11 +12 -0
  53. data/tests/data/parser/multipart.12 +12 -0
  54. data/tests/data/parser/multipart.13 +6 -0
  55. data/tests/data/parser/multipart.14 +6 -0
  56. data/tests/data/parser/multipart.15 +6 -0
  57. data/tests/data/parser/multipart.16 +6 -0
  58. data/tests/data/parser/multipart.2 +8 -0
  59. data/tests/data/parser/multipart.3 +5 -0
  60. data/tests/data/parser/multipart.4 +6 -0
  61. data/tests/data/parser/multipart.5 +4 -0
  62. data/tests/data/parser/multipart.6 +5 -0
  63. data/tests/data/parser/multipart.7 +6 -0
  64. data/tests/data/parser/multipart.8 +8 -0
  65. data/tests/data/parser/multipart.9 +7 -0
  66. data/tests/data/transparency/absolute.1 +5 -0
  67. data/tests/data/transparency/absolute.2 +1 -0
  68. data/tests/data/transparency/absolute.3 +2 -0
  69. data/tests/data/transparency/absolute.4 +3 -0
  70. data/tests/data/transparency/absolute.5 +4 -0
  71. data/tests/data/transparency/absolute.6 +49 -0
  72. data/tests/data/transparency/message.1 +73 -0
  73. data/tests/data/transparency/message.2 +34 -0
  74. data/tests/data/transparency/message.3 +63 -0
  75. data/tests/data/transparency/message.4 +5 -0
  76. data/tests/data/transparency/message.5 +15 -0
  77. data/tests/data/transparency/message.6 +1185 -0
  78. data/tests/runtests.rb +35 -0
  79. data/tests/testaddress.rb +1192 -0
  80. data/tests/testbase.rb +207 -0
  81. data/tests/testheader.rb +1207 -0
  82. data/tests/testmailbox.rb +47 -0
  83. data/tests/testmboxreader.rb +161 -0
  84. data/tests/testmessage.rb +257 -0
  85. data/tests/testparser.rb +634 -0
  86. data/tests/testparsermultipart.rb +205 -0
  87. data/tests/testpushbackreader.rb +40 -0
  88. data/tests/testserialize.rb +264 -0
  89. data/tests/testtestbase.rb +112 -0
  90. data/tests/testtranspparency.rb +105 -0
  91. metadata +143 -0
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright (C) 2001, 2002, 2003 Matt Armstrong. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # 2. Redistributions in binary form must reproduce the above copyright
11
+ # notice, this list of conditions and the following disclaimer in the
12
+ # documentation and/or other materials provided with the distribution.
13
+ # 3. The name of the author may not be used to endorse or promote products
14
+ # derived from this software without specific prior written permission.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19
+ # NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ #
27
+
28
+ # Base for all the test cases, providing a default setup and teardown
29
+
30
+ require 'rubyunit'
31
+ require 'rbconfig.rb'
32
+ require 'tempfile'
33
+ require 'find'
34
+ require 'ftools'
35
+
36
+ begin
37
+ require 'pp'
38
+ rescue LoadError
39
+ end
40
+
41
+ class TestBase < RUNIT::TestCase
42
+ include Config
43
+
44
+ attr_reader :scratch_dir
45
+
46
+ # NoMethodError was introduced in ruby 1.7
47
+ NO_METHOD_ERROR = if RUBY_VERSION >= "1.7"
48
+ NoMethodError
49
+ else
50
+ NameError
51
+ end
52
+
53
+ # Print a string to a temporary file and return the file opened.
54
+ # This lets you have some test data in a string, but access it with
55
+ # a file.
56
+ def string_as_file(string, strip_whitespace = true)
57
+ if strip_whitespace
58
+ temp = ""
59
+ string.each_line { |line|
60
+ temp += line.sub(/^[ \t]+/, '')
61
+ }
62
+ string = temp
63
+ end
64
+ file = Tempfile.new("ruby.string_as_file.")
65
+ begin
66
+ file.print(string)
67
+ file.close()
68
+ file.open()
69
+ yield file
70
+ ensure
71
+ file.close(true)
72
+ end
73
+ end
74
+
75
+ # Return true if the given file contains a line matching regexp
76
+ def file_contains(filename, regexp)
77
+ unless regexp.kind_of?(Regexp)
78
+ regexp = Regexp.new(regexp)
79
+ end
80
+ detected = nil
81
+ File.open(filename) { |f|
82
+ detected = f.detect { |line|
83
+ line =~ regexp
84
+ }
85
+ }
86
+ ! detected.nil?
87
+ end
88
+
89
+ # Deletes everything in directory +dir+, including any
90
+ # subdirectories
91
+ def cleandir(dir)
92
+ if FileTest.directory?(dir)
93
+ files = []
94
+ Find.find(dir) { |f|
95
+ files.push(f)
96
+ }
97
+ files.shift # get rid of 'dir'
98
+ files.reverse_each { |f|
99
+ if FileTest.directory?(f)
100
+ Dir.delete(f)
101
+ else
102
+ File.delete(f)
103
+ end
104
+ }
105
+ end
106
+ end
107
+
108
+ def setup
109
+ @scratch_dir = File.join(Dir.getwd, "_scratch_" + name)
110
+ @data_dir = File.join(Dir.getwd, "tests", "data")
111
+ @scratch_hash = {}
112
+
113
+ cleandir(@scratch_dir)
114
+ Dir.rmdir(@scratch_dir) if FileTest.directory?(@scratch_dir)
115
+ Dir.mkdir(@scratch_dir) unless FileTest.directory?(@scratch_dir)
116
+ end
117
+
118
+ def ruby_program
119
+ File.join(CONFIG['bindir'], CONFIG['ruby_install_name'])
120
+ end
121
+
122
+ def data_filename(name)
123
+ File.join(@data_dir, name)
124
+ end
125
+
126
+ def data_as_file(name)
127
+ unless name =~ %r{^/}
128
+ name = data_filename(name)
129
+ end
130
+ File.open(name) { |f|
131
+ yield f
132
+ }
133
+ rescue Errno::ENOENT
134
+ assert_fail("data file #{name.inspect} does not exist")
135
+ end
136
+
137
+ def data_as_string(name)
138
+ data_as_file(name) { |f|
139
+ f.read
140
+ }
141
+ end
142
+
143
+ def scratch_filename(name)
144
+ if @scratch_hash.key?(name)
145
+ temp = @scratch_hash[name]
146
+ temp = temp.succ
147
+ @scratch_hash[name] = name = temp
148
+ else
149
+ temp = name.dup
150
+ temp << '.0' unless temp =~ /\.\d+$/
151
+ @scratch_hash[name] = temp
152
+ end
153
+ File.join(@scratch_dir, name)
154
+ end
155
+
156
+ def scratch_file_write(name)
157
+ name = scratch_filename(name)
158
+ File.open(name, 'w') { |f|
159
+ yield f
160
+ }
161
+ end
162
+
163
+ def teardown
164
+ unless $! || ((defined? passed?) && !passed?)
165
+ cleandir(@scratch_dir)
166
+ Dir.rmdir(@scratch_dir) if FileTest.directory?(@scratch_dir)
167
+ end
168
+ end
169
+
170
+ def call_fails(arg, &block)
171
+ begin
172
+ yield arg
173
+ rescue Exception
174
+ return true
175
+ end
176
+ return false
177
+ end
178
+
179
+ # if a random string failes, run it through this function to find the
180
+ # shortest fail case
181
+ def find_shortest_failure(str, &block)
182
+ unless call_fails(str, &block)
183
+ raise "hey, the input didn't fail!"
184
+ else
185
+ # Chop off stuff from the beginning and then the end
186
+ # until it stops failing
187
+ bad = str
188
+ 0.upto(bad.length) {|index|
189
+ bad.length.downto(1) {|length|
190
+ begin
191
+ loop {
192
+ s = bad.dup
193
+ s[index,length] = ''
194
+ break if bad == s
195
+ break unless call_fails(s, &block)
196
+ bad = s
197
+ }
198
+ rescue IndexError
199
+ break
200
+ end
201
+ }
202
+ }
203
+ raise "shortest failure is #{bad.inspect}"
204
+ end
205
+ end
206
+
207
+ end
@@ -0,0 +1,1207 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright (C) 2001, 2002, 2003, 2004 Matt Armstrong. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # 2. Redistributions in binary form must reproduce the above copyright
11
+ # notice, this list of conditions and the following disclaimer in the
12
+ # documentation and/or other materials provided with the distribution.
13
+ # 3. The name of the author may not be used to endorse or promote products
14
+ # derived from this software without specific prior written permission.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19
+ # NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ #
27
+
28
+ require 'tests/testbase'
29
+ require 'rmail/header'
30
+
31
+ class TestRMailHeader < TestBase
32
+
33
+ def test_AREF # '[]'
34
+ h = RMail::Header.new
35
+ h['From'] = 'setting1'
36
+ h['From'] = 'setting2'
37
+ h['From'] = 'setting3'
38
+
39
+ assert_equal('setting1', h[0])
40
+ assert_equal('setting2', h[1])
41
+ assert_equal('setting3', h[2])
42
+ assert_equal('setting1', h['From'])
43
+ assert_equal('setting1', h['from'])
44
+ assert_equal('setting1', h['FROM'])
45
+ assert_equal('setting1', h['From:'])
46
+ assert_equal('setting1', h['From : '])
47
+ assert_nil(h['From '])
48
+ assert_nil(h[' From '])
49
+ assert_nil(h[' From : '])
50
+ end
51
+
52
+ def test_ASET # '[]='
53
+
54
+ #
55
+ # Test that the object stores the exact objects we pass it in (at
56
+ # least, when they are strings) and that it freezes them.
57
+ #
58
+ bob = "Bob"
59
+ bob_value = "bobvalue"
60
+ sally = "Sally"
61
+ sally_value = "sallyvalue"
62
+ h = RMail::Header.new
63
+
64
+ assert_same(bob_value, h[bob] = bob_value)
65
+ assert_same(sally_value, h[sally] = sally_value)
66
+
67
+ h.each_with_index do |pair, index|
68
+ case index
69
+ when 0
70
+ assert_equal(bob, pair[0])
71
+ assert_equal(bob_value, pair[1])
72
+ assert(pair[0].frozen?)
73
+ assert(pair[1].frozen?)
74
+ when 1
75
+ assert_equal(sally, pair[0])
76
+ assert_equal(sally_value, pair[1])
77
+ assert(pair[0].frozen?)
78
+ assert(pair[1].frozen?)
79
+ else
80
+ raise
81
+ end
82
+ end
83
+
84
+ # Test that passing in symbols will not get converted into strings
85
+ # strings
86
+ h = RMail::Header.new
87
+ assert_exception(NO_METHOD_ERROR) {
88
+ h[:Kelly] = :the_value
89
+ }
90
+
91
+ # Test that the : will be stripped
92
+ h = RMail::Header.new
93
+ h["bob:"] = "bob"
94
+ h["sally : "] = "sally"
95
+ h.each_with_index do |pair, index|
96
+ case index
97
+ when 0
98
+ assert_equal("bob", pair[0])
99
+ assert_equal("bob", pair[1])
100
+ when 1
101
+ assert_equal("sally", pair[0])
102
+ assert_equal("sally", pair[1])
103
+ else
104
+ raise
105
+ end
106
+ end
107
+ end
108
+
109
+ def test_EQUAL # '=='
110
+ h1 = RMail::Header.new
111
+ h2 = RMail::Header.new
112
+ assert_equal(h1, h2)
113
+ assert_equal(h2, h1)
114
+
115
+ h1['foo'] = 'a'
116
+ h2['FOO'] = 'a'
117
+ h1['bar'] = 'b'
118
+ h2['bar'] = 'b'
119
+ assert_equal(h1, h2)
120
+ assert_equal(h2, h1)
121
+
122
+ h1 = RMail::Header.new
123
+ h2 = RMail::Header.new
124
+ h1['foo'] = 'a'
125
+ h2['foo'] = 'b'
126
+ assert(! (h1 == h2))
127
+ assert(! (h2 == h1))
128
+
129
+ h1 = RMail::Header.new
130
+ h2 = RMail::Header.new
131
+ h1['foo'] = 'a'
132
+ h2['foo'] = 'a'
133
+ h1.mbox_from = "From bo diddly"
134
+ assert(! (h1 == h2))
135
+ assert(! (h2 == h1))
136
+
137
+ h1 = RMail::Header.new
138
+ assert(! (h1 == Object.new))
139
+ assert(! (h1 == Hash.new))
140
+ assert(! (h1 == Array.new))
141
+ end
142
+
143
+ def test_add
144
+ #
145
+ # Test that the object stores the exact objects we pass it in (at
146
+ # least, when they are strings) and that it freezes them.
147
+ #
148
+ bob = "Bob"
149
+ bob_value = "bobvalue"
150
+ sally = "Sally"
151
+ sally_value = "sallyvalue"
152
+ h = RMail::Header.new
153
+
154
+ assert_same(h, h.add(bob, bob_value))
155
+ assert_same(h, h.add(sally, sally_value))
156
+
157
+ h.each_with_index do |pair, index|
158
+ case index
159
+ when 0
160
+ assert_equal(bob, pair[0])
161
+ assert_equal(bob_value, pair[1])
162
+ assert(pair[0].frozen?)
163
+ assert(pair[1].frozen?)
164
+ when 1
165
+ assert_equal(sally, pair[0])
166
+ assert_equal(sally_value, pair[1])
167
+ assert(pair[0].frozen?)
168
+ assert(pair[1].frozen?)
169
+ else
170
+ raise
171
+ end
172
+ end
173
+
174
+ # Test that passing in symbol values raises an exception
175
+ h = RMail::Header.new
176
+ assert_exception(NO_METHOD_ERROR) {
177
+ assert_same(h, h.add("bob", :the_value))
178
+ }
179
+
180
+ # Test that we can put stuff in arbitrary locations
181
+ h = RMail::Header.new
182
+ assert_same(h, h.add("last", "last value"))
183
+ assert_same(h, h.add("first", "first value", 0))
184
+ assert_same(h, h.add("middle", "middle value", 1))
185
+
186
+ h.each_with_index do |pair, index|
187
+ case index
188
+ when 0
189
+ assert_equal("first", pair[0])
190
+ assert_equal("first value", pair[1])
191
+ when 1
192
+ assert_equal("middle", pair[0])
193
+ assert_equal("middle value", pair[1])
194
+ when 2
195
+ assert_equal("last", pair[0])
196
+ assert_equal("last value", pair[1])
197
+ else
198
+ raise
199
+ end
200
+ end
201
+
202
+ # Test the params argument
203
+ h = RMail::Header.new
204
+ h.add("name", "value", nil, 'param1' => 'value1', 'param2' => '+value2')
205
+ assert_equal('value; param1=value1; param2="+value2"', h['name'])
206
+
207
+ h = RMail::Header.new
208
+ h.add_raw("MIME-Version: 1.0")
209
+ h.add_raw("Content-Type: multipart/alternative; boundary=X")
210
+ assert_match(/\b1\.0\b/, h['mime-version:'])
211
+ assert_not_nil(h.param('content-type', 'boundary'))
212
+ assert_equal("multipart", h.media_type)
213
+ end
214
+
215
+ def test_set
216
+ # Test that set works like delete+add
217
+
218
+ h = RMail::Header.new
219
+ h.add_raw("Foo: Bar")
220
+ h.set('foo', 'expected')
221
+ assert_equal('expected', h['foo'])
222
+ assert_equal(1, h.length)
223
+
224
+ h = RMail::Header.new
225
+ h.set('foo', 'expected')
226
+ assert_equal('expected', h['foo'])
227
+ assert_equal(1, h.length)
228
+
229
+ end
230
+
231
+ def test_clear
232
+ # Test that we can put stuff in arbitrary locations
233
+ h = RMail::Header.new
234
+ h.add("first", "first value", 0)
235
+ h.add("middle", "middle value", 1)
236
+ h.add("last", "last value")
237
+ h.mbox_from = "mbox from"
238
+ assert_equal(3, h.length)
239
+ assert_same(h, h.clear)
240
+ assert_equal(0, h.length)
241
+ assert_equal(nil, h['first'])
242
+ assert_equal(nil, h['middle'])
243
+ assert_equal(nil, h['last'])
244
+ assert_equal(nil, h[0])
245
+ assert_equal(nil, h[1])
246
+ assert_equal(nil, h[2])
247
+ assert_equal(nil, h.mbox_from)
248
+ end
249
+
250
+ def test_dup
251
+ h1 = RMail::Header.new
252
+ h1["field1"] = "field1 value"
253
+ h1.mbox_from = "mbox from"
254
+ h2 = h1.dup
255
+ assert(! h1.equal?(h2))
256
+ assert_equal(h1, h2)
257
+ assert_same(h1.mbox_from, h2.mbox_from)
258
+
259
+ h1.each_with_index do |pair, index|
260
+ assert_same(h1[index], h2[index])
261
+ case index
262
+ when 0
263
+ assert_equal("field1", pair[0])
264
+ assert_equal("field1 value", pair[1])
265
+ else
266
+ raise
267
+ end
268
+ end
269
+
270
+ h2.mbox_from = "bob"
271
+ assert_equal("mbox from", h1.mbox_from)
272
+
273
+ h1["field2"] = "field2 value"
274
+ assert_equal("field2 value", h1["field2"])
275
+ assert_nil(h2["field2"])
276
+
277
+ # Make sure singleton methods are not carried over through a dup
278
+ def h1.my_singleton_method
279
+ end
280
+ assert_respond_to(:my_singleton_method, h1)
281
+ h2 = h1.dup
282
+ assert(! h2.respond_to?(:my_singleton_method))
283
+ end
284
+
285
+ def test_clone
286
+ h1 = RMail::Header.new
287
+ h1["field1"] = "field1 value"
288
+ h1.mbox_from = "mbox from"
289
+ h2 = h1.clone
290
+ assert(! h1.equal?(h2))
291
+ assert_equal(h1, h2)
292
+ assert_equal(h1.mbox_from, h2.mbox_from)
293
+ assert(! h1.mbox_from.equal?(h2.mbox_from))
294
+
295
+ h1.each_with_index do |pair, index|
296
+ assert_equal(h1[index], h2[index])
297
+ assert(! h1[index].equal?(h2[index]))
298
+ case index
299
+ when 0
300
+ assert_equal("field1", pair[0])
301
+ assert_equal("field1 value", pair[1])
302
+ else
303
+ raise
304
+ end
305
+ end
306
+
307
+ h2.mbox_from = "bob"
308
+ assert_equal("mbox from", h1.mbox_from)
309
+
310
+ h1["field2"] = "field2 value"
311
+ assert_equal("field2 value", h1["field2"])
312
+ assert_nil(h2["field2"])
313
+
314
+ # Make sure singleton methods are carried over through a clone
315
+ h1 = RMail::Header.new
316
+ def h1.my_singleton_method
317
+ end
318
+ assert_respond_to(:my_singleton_method, h1)
319
+ h2 = h1.clone
320
+ assert(!h1.equal?(h2))
321
+ assert_respond_to(:my_singleton_method, h2)
322
+ end
323
+
324
+ def test_replace
325
+ h1 = RMail::Header.new
326
+ h1['From'] = "bob@example.net"
327
+ h1['To'] = "sam@example.net"
328
+ h1.mbox_from = "mbox from"
329
+
330
+ h2 = RMail::Header.new
331
+ h2['From'] = "sally@example.net"
332
+ h2.mbox_from = "h2 mbox from"
333
+
334
+ assert_same(h2, h2.replace(h1))
335
+ assert_equal(h1, h2)
336
+ assert_same(h1['From'], h2['From'])
337
+ assert_same(h1['To'], h2['To'])
338
+ assert_same(h1.mbox_from, h2.mbox_from)
339
+
340
+ e = assert_exception(TypeError) {
341
+ h2.replace("hi mom")
342
+ }
343
+ assert_equal('String is not of type RMail::Header', e.message)
344
+ end
345
+
346
+ def test_delete
347
+ h = RMail::Header.new
348
+ h['Foo'] = 'bar'
349
+ h['Bazo'] = 'bingo'
350
+ h['Foo'] = 'yo'
351
+ assert_same(h, h.delete('Foo'))
352
+ assert_nil(h['Foo'])
353
+ assert_equal('bingo', h[0])
354
+ assert_equal(1, h.length)
355
+ end
356
+
357
+ def test_delete_at
358
+ h = RMail::Header.new
359
+ h['Foo'] = 'bar'
360
+ h['Bazo'] = 'bingo'
361
+ h['Foo'] = 'yo'
362
+ assert_same(h, h.delete_at(1))
363
+ assert_nil(h['Bazo'])
364
+ assert_equal('bar', h[0])
365
+ assert_equal('yo', h[1])
366
+ assert_equal(2, h.length)
367
+
368
+ assert_exception(TypeError) {
369
+ h.delete_at("1")
370
+ }
371
+ end
372
+
373
+ def test_delete_if
374
+ h = RMail::Header.new
375
+ h['Foo'] = 'bar'
376
+ h['Bazo'] = 'bingo'
377
+ h['Foo'] = 'yo'
378
+ assert_same(h, h.delete_if { |n, v| v =~ /^b/ })
379
+ assert_nil(h['Bazo'])
380
+ assert_equal('yo', h['Foo'])
381
+ assert_equal(1, h.length)
382
+
383
+ assert_exception(LocalJumpError) {
384
+ h.delete_if
385
+ }
386
+ end
387
+
388
+ def each_helper(method)
389
+ h = RMail::Header.new
390
+ h['name1'] = 'value1'
391
+ h['name2'] = 'value2'
392
+
393
+ i = 1
394
+ h.send(method) { |n, v|
395
+ assert_equal("name#{i}", n)
396
+ assert_equal("value#{i}", v)
397
+ i += 1
398
+ }
399
+
400
+ assert_exception(LocalJumpError) {
401
+ h.send(method)
402
+ }
403
+ end
404
+
405
+ def test_each
406
+ each_helper(:each)
407
+ end
408
+
409
+ def test_each_pair
410
+ each_helper(:each_pair)
411
+ end
412
+
413
+ def each_name_helper(method)
414
+ h = RMail::Header.new
415
+ h['name1'] = 'value1'
416
+ h['name2'] = 'value2'
417
+
418
+ i = 1
419
+ h.send(method) { |n|
420
+ assert_equal("name#{i}", n)
421
+ i += 1
422
+ }
423
+
424
+ assert_exception(LocalJumpError) {
425
+ h.send(method)
426
+ }
427
+ end
428
+
429
+ def test_each_name
430
+ each_name_helper(:each_name)
431
+ end
432
+
433
+ def test_each_key
434
+ each_name_helper(:each_key)
435
+ end
436
+
437
+ def test_each_value
438
+ h = RMail::Header.new
439
+ h['name1'] = 'value1'
440
+ h['name2'] = 'value2'
441
+
442
+ i = 1
443
+ h.each_value { |v|
444
+ assert_equal("value#{i}", v)
445
+ i += 1
446
+ }
447
+
448
+ assert_exception(LocalJumpError) {
449
+ h.each_value
450
+ }
451
+ end
452
+
453
+ def test_empty?
454
+ h = RMail::Header.new
455
+ assert(h.empty?)
456
+ h['To'] = "president@example.com"
457
+ assert_equal(false, h.empty?)
458
+ end
459
+
460
+ def test_fetch
461
+ h = RMail::Header.new
462
+ h['To'] = "bob@example.net"
463
+ h['To'] = "sally@example.net"
464
+
465
+ assert_equal("bob@example.net", h.fetch('to'))
466
+ assert_equal(1, h.fetch('notthere', 1))
467
+ assert_equal(2, h.fetch('notthere', 1) { 2 })
468
+
469
+ e = assert_exception(ArgumentError) {
470
+ h.fetch(1,2,3)
471
+ }
472
+ assert_equal('wrong # of arguments(3 for 2)', e.message)
473
+ end
474
+
475
+ def test_fetch_all
476
+ h = RMail::Header.new
477
+ h['To'] = "bob@example.net"
478
+ h['To'] = "sally@example.net"
479
+
480
+ assert_equal([ "bob@example.net", "sally@example.net" ],
481
+ h.fetch_all('to'))
482
+ assert_equal(1, h.fetch('notthere', 1))
483
+ assert_equal(2, h.fetch('notthere', 1) { 2 })
484
+
485
+ e = assert_exception(ArgumentError) {
486
+ h.fetch_all(1,2,3)
487
+ }
488
+ assert_equal('wrong # of arguments(3 for 2)', e.message)
489
+ end
490
+
491
+ def field_helper(method)
492
+ h = RMail::Header.new
493
+ h['Subject'] = 'the sky is blue'
494
+ assert(h.send(method, 'Subject'))
495
+ assert_equal(false, h.send(method, 'Return-Path'))
496
+ end
497
+
498
+ def test_field?
499
+ field_helper(:field?)
500
+ end
501
+
502
+ def test_has_key?
503
+ field_helper(:has_key?)
504
+ end
505
+
506
+ def test_include?
507
+ field_helper(:include?)
508
+ end
509
+
510
+ def test_member?
511
+ field_helper(:member?)
512
+ end
513
+
514
+ def test_key?
515
+ field_helper(:key?)
516
+ end
517
+
518
+ def test_select
519
+ h = RMail::Header.new
520
+ h['To'] = 'matt@example.net'
521
+ h['From'] = 'bob@example.net'
522
+ h['Subject'] = 'test_select'
523
+
524
+ assert_equal([ [ 'To', 'matt@example.net' ],
525
+ [ 'From', 'bob@example.net' ] ],
526
+ h.select('To', 'From'))
527
+ assert_equal([], h.select)
528
+ end
529
+
530
+ def names_helper(method)
531
+ h = RMail::Header.new
532
+ assert_equal([], h.send(method))
533
+ h['To'] = 'matt@example.net'
534
+ h['from'] = 'bob@example.net'
535
+ h['SUBJECT'] = 'test_select'
536
+ assert_equal([ 'To', 'from', 'SUBJECT' ], h.send(method))
537
+ end
538
+
539
+ def test_names
540
+ names_helper(:names)
541
+ end
542
+
543
+ def test_keys
544
+ names_helper(:keys)
545
+ end
546
+
547
+ def length_helper(method)
548
+ h = RMail::Header.new
549
+ assert_equal(0, h.send(method))
550
+ h['To'] = 'matt@example.net'
551
+ assert_equal(1, h.send(method))
552
+ h['from'] = 'bob@example.net'
553
+ assert_equal(2, h.send(method))
554
+ h['SUBJECT'] = 'test_select'
555
+ assert_equal(3, h.send(method))
556
+ h.mbox_from = "foo"
557
+ assert_equal(3, h.send(method))
558
+ h.delete('from')
559
+ assert_equal(2, h.send(method))
560
+ end
561
+
562
+ def test_length
563
+ length_helper(:length)
564
+ end
565
+
566
+ def test_size
567
+ length_helper(:size)
568
+ end
569
+
570
+ def test_to_a
571
+ h = RMail::Header.new
572
+ assert_equal([ ], h.to_a)
573
+ h['To'] = 'to value'
574
+ h['From'] = 'from value'
575
+ assert_equal([ [ 'To', 'to value' ],
576
+ [ 'From', 'from value' ] ], h.to_a)
577
+ end
578
+
579
+ def test_to_string
580
+ h = RMail::Header.new
581
+ assert_equal("", h.to_string(true))
582
+ assert_equal("", h.to_string(false))
583
+ assert_equal(h.to_s, h.to_string(true))
584
+
585
+ h['To'] = 'matt@example.net'
586
+ assert_equal("To: matt@example.net\n", h.to_string(true))
587
+ assert_equal("To: matt@example.net\n", h.to_string(false))
588
+ assert_equal(h.to_s, h.to_string(true))
589
+
590
+ h.mbox_from = "From matt@example.net blah blah"
591
+ assert_equal(<<EOF, h.to_string(true))
592
+ From matt@example.net blah blah
593
+ To: matt@example.net
594
+ EOF
595
+ assert_equal("To: matt@example.net\n", h.to_string(false))
596
+ assert_equal(h.to_s, h.to_string(true))
597
+ end
598
+
599
+ def test_s_new
600
+ h = RMail::Header.new
601
+ assert_instance_of(RMail::Header, h)
602
+ assert_equal(0, h.length)
603
+ assert_nil(h[0])
604
+ end
605
+
606
+ def test_mbox_from()
607
+ h = RMail::Header.new
608
+ assert_nil(h.mbox_from)
609
+
610
+ # FIXME: should do some basic sanity checks on its argument.
611
+
612
+ s = "foo bar baz"
613
+ assert_same(s, h.mbox_from = s)
614
+ assert_equal(s, h.mbox_from)
615
+
616
+ assert_equal(nil, h.mbox_from = nil)
617
+ assert_equal(nil, h.mbox_from)
618
+ end
619
+
620
+ # Compare header contents against an expected result. 'result'
621
+ # should be an array of arrays, with the first element being the
622
+ # required key name and the second element being the whole line.
623
+ def compare_header(header, result)
624
+ index = -1
625
+ header.each_with_index { |value, index|
626
+ assert_operator(index, '<', result.length,
627
+ "result has too few elements")
628
+ assert_operator(2, '<=', result[index].length,
629
+ "Expected result item must have at last two elements.")
630
+ assert_operator(3, '>=', result[index].length,
631
+ "Expected result item must have no more than three " +
632
+ "elements.")
633
+ assert_equal(2, value.length)
634
+
635
+ expected_tag, expected_header = result[index]
636
+ got_tag, got_header = value
637
+
638
+ assert_equal(header[index], got_header)
639
+
640
+ assert_equal(expected_tag, got_tag,
641
+ "field #{index} has incorrect name")
642
+ assert_equal(expected_header, got_header,
643
+ "field #{index} has incorrect line, " +
644
+ "expected #{expected_header.inspect} got " +
645
+ "#{got_header.inspect}")
646
+ assert_equal(header[expected_tag], expected_header)
647
+ }
648
+ assert_equal(index + 1, result.length,
649
+ "result has too few elements (#{index} < #{result.length})")
650
+ end
651
+
652
+ def verify_match(header, name, value, expected_result)
653
+ h = header.match(name, value)
654
+ assert_kind_of(RMail::Header, h)
655
+ if h.length == 0
656
+ assert_equal(expected_result, nil)
657
+ else
658
+ assert_not_nil(expected_result)
659
+ compare_header(h, expected_result)
660
+ end
661
+ end
662
+
663
+ def test_match
664
+ h = RMail::Header.new
665
+ h['To'] = 'bob@example.net'
666
+ h['Cc'] = 'sammy@example.com'
667
+ h['Resent-To'] = 'president@example.com'
668
+ h['Subject'] = 'yoda lives!'
669
+
670
+ # First verify argument type checking
671
+ e = assert_exception(ArgumentError) {
672
+ h.match(12, "foo")
673
+ }
674
+ assert_match(/name not a Regexp or String/, e.message)
675
+ assert_no_exception {
676
+ h.match(/not_case_insensitive/, "foo")
677
+ }
678
+ e = assert_exception(ArgumentError) {
679
+ h.match(/this is okay/i, 12)
680
+ }
681
+ assert_match(/value not a Regexp or String/, e.message)
682
+ assert_no_exception {
683
+ h.match(/this is okay/i, /this_not_multiline_or_insensitive/)
684
+ }
685
+ assert_no_exception {
686
+ h.match(/this is okay/i, /this_not_multiline/i)
687
+ }
688
+ assert_no_exception {
689
+ h.match(/this is okay/i, /this_not_inesnsitive/m)
690
+ }
691
+
692
+ verify_match(h, /./i, /this will not match anything/im, nil)
693
+
694
+ verify_match(h, "to", /./im,
695
+ [ [ 'To', "bob@example.net" ] ])
696
+
697
+ verify_match(h, "tO", /./im,
698
+ [ [ 'To', "bob@example.net" ] ])
699
+
700
+ verify_match(h, "To", /./im,
701
+ [ [ 'To', "bob@example.net" ] ])
702
+
703
+ verify_match(h, "^to", /./im, nil)
704
+
705
+ verify_match(h, /^(to|cc|resent-to)/i, /.*/im,
706
+ [ [ 'To', "bob@example.net" ],
707
+ [ 'Cc', "sammy@example.com" ],
708
+ [ 'Resent-To', "president@example.com"] ])
709
+ end
710
+
711
+ def test_match?
712
+ h = RMail::Header.new
713
+ h['To'] = 'bob@example.net'
714
+ h['Cc'] = 'sammy@example.com'
715
+ h['Resent-To'] = 'president@example.com'
716
+ h['Subject'] = "yoda\n lives! [bob]\\s"
717
+
718
+ # First verify argument type checking
719
+ e = assert_exception(ArgumentError) {
720
+ h.match?(12, "foo")
721
+ }
722
+ assert_match(/name not a Regexp or String/, e.message)
723
+ assert_no_exception {
724
+ h.match?(/not_case_insensitive/, "foo")
725
+ }
726
+ e = assert_exception(ArgumentError) {
727
+ h.match?(/this is okay/i, 12)
728
+ }
729
+ assert_match(/value not a Regexp or String/, e.message)
730
+ assert_no_exception {
731
+ h.match?(/this is okay/i, /this_not_multiline_or_insensitive/)
732
+ }
733
+ assert_no_exception {
734
+ h.match?(/this is okay/i, /this_not_multiline/i)
735
+ }
736
+ assert_no_exception {
737
+ h.match?(/this is okay/i, /this_not_inesnsitive/m)
738
+ }
739
+
740
+ assert_equal(false, h.match?(/./i, /this will not match anything/im))
741
+ assert_equal(true, h.match?("to", /./im))
742
+ assert_equal(true, h.match?("To", /./im))
743
+ assert_equal(false, h.match?("^to", /./im))
744
+ assert_equal(true, h.match?(/^(to|cc|resent-to)/i, /.*/im))
745
+ assert_equal(true, h.match?('subject', 'yoda'))
746
+ assert_equal(true, h.match?('subject', /yoda\s+lives/))
747
+ assert_equal(true, h.match?('subject', '[bob]\s'))
748
+ assert_equal(true, h.match?('subject', '[BOB]\s'))
749
+ end
750
+
751
+ def test_content_type
752
+ h = RMail::Header.new
753
+ assert_equal(nil, h.content_type)
754
+
755
+ h['content-type'] = ' text/html; charset=ISO-8859-1'
756
+ assert_equal("text/html", h.content_type)
757
+
758
+ h.delete('content-type')
759
+ h['content-type'] = ' foo/html ; charset=ISO-8859-1'
760
+ assert_equal("foo/html", h.content_type)
761
+ end
762
+
763
+ def test_media_type
764
+ h = RMail::Header.new
765
+ assert_nil(h.media_type)
766
+ assert_equal("foo", h.media_type("foo"))
767
+ assert_equal("bar", h.media_type("foo") { "bar" })
768
+
769
+ h['content-type'] = ' text/html; charset=ISO-8859-1'
770
+ assert_equal("text", h.media_type)
771
+
772
+ h.delete('content-type')
773
+ h['content-type'] = 'foo/html ; charset=ISO-8859-1'
774
+ assert_equal("foo", h.media_type)
775
+ end
776
+
777
+ def test_subtype
778
+ h = RMail::Header.new
779
+ assert_nil(h.subtype)
780
+ assert_equal("foo", h.subtype("foo"))
781
+ assert_equal("bar", h.subtype("foo") { "bar" })
782
+
783
+ h['content-type'] = ' text/html; charset=ISO-8859-1'
784
+ assert_equal("html", h.subtype)
785
+
786
+ h.delete('content-type')
787
+ h['content-type'] = 'foo/yoda ; charset=ISO-8859-1'
788
+ assert_equal("yoda", h.subtype)
789
+ end
790
+
791
+ def test_params
792
+ begin
793
+ h = RMail::Header.new
794
+ assert_nil(h.params('foo'))
795
+ assert_nil(h.params('foo', nil))
796
+
797
+ default = "foo"
798
+ ignore = "ignore"
799
+ assert_same(default, h.params('foo', default))
800
+ assert_same(default, h.params('foo') { |field_name|
801
+ assert_equal('foo', field_name)
802
+ default
803
+ })
804
+ assert_same(default, h.params('foo', ignore) {
805
+ default
806
+ })
807
+ end
808
+
809
+ begin
810
+ h = RMail::Header.new
811
+ h['Content-Disposition'] = 'attachment;
812
+ filename="delete_product_recover_flag.cmd"'
813
+ assert_equal( { "filename" => "delete_product_recover_flag.cmd" },
814
+ h.params('content-disposition'))
815
+ end
816
+
817
+ begin
818
+ h = RMail::Header.new
819
+ h['Content-Disposition'] = 'attachment;
820
+ filename="delete=_product=_recover;_flag;.cmd"'
821
+ assert_equal( { "filename" => "delete=_product=_recover;_flag;.cmd" },
822
+ h.params('content-disposition'))
823
+ end
824
+
825
+ begin
826
+ h = RMail::Header.new
827
+ h['Content-Disposition'] = ' attachment ;
828
+ filename = "trailing_Whitespace.cmd" '
829
+ assert_equal( { "filename" => "trailing_Whitespace.cmd" },
830
+ h.params('content-disposition'))
831
+ end
832
+
833
+ begin
834
+ h = RMail::Header.new
835
+ h['Content-Disposition'] = ''
836
+ assert_equal({}, h.params('content-disposition'))
837
+ end
838
+
839
+ begin
840
+ h = RMail::Header.new
841
+ h['Content-Disposition'] = ' '
842
+ assert_equal({}, h.params('content-disposition'))
843
+ end
844
+
845
+ begin
846
+ h = RMail::Header.new
847
+ h['Content-Disposition'] = '='
848
+ assert_equal({}, h.params('content-disposition'))
849
+ end
850
+
851
+ begin
852
+ h = RMail::Header.new
853
+ h['Content-Disposition'] = 'ass; param1 = "p1"; param2 = "p2"'
854
+ assert_equal({ 'param1' => 'p1',
855
+ 'param2' => 'p2' }, h.params('content-disposition'))
856
+ end
857
+
858
+ begin
859
+ h = RMail::Header.new
860
+ h['Content-Disposition'] = 'ass; Foo = "" ; bar = "asdf"'
861
+ assert_equal({ "foo" => '""',
862
+ "bar" => "asdf" }, h.params('content-disposition'))
863
+ end
864
+ end
865
+
866
+ def test_set_boundary
867
+ begin
868
+ h = RMail::Header.new
869
+ h.set_boundary("b")
870
+ assert_equal("b", h.param('content-type', 'boundary'))
871
+ assert_equal("multipart/mixed", h.content_type)
872
+ assert_equal('multipart/mixed; boundary=b', h['content-type'])
873
+ end
874
+
875
+ begin
876
+ h = RMail::Header.new
877
+ h['content-type'] = "multipart/alternative"
878
+ h.set_boundary("b")
879
+ assert_equal("b", h.param('content-type', 'boundary'))
880
+ assert_equal("multipart/alternative", h.content_type)
881
+ assert_equal('multipart/alternative; boundary=b', h['content-type'])
882
+ end
883
+
884
+ begin
885
+ h = RMail::Header.new
886
+ h['content-type'] = 'multipart/alternative; boundary="a"'
887
+ h.set_boundary("b")
888
+ assert_equal("b", h.param('content-type', 'boundary'))
889
+ assert_equal("multipart/alternative", h.content_type)
890
+ assert_equal('multipart/alternative; boundary=b', h['content-type'])
891
+ end
892
+
893
+ end
894
+
895
+ def test_params_random_string
896
+ # find_shortest_failure("],C05w\010O\e]b\">%\023[1{:L1o>B\"|\024fDJ@u{)\\\021\t\036\034)ZJ\034&/+]owh=?{Yc)}vi\000\"=@b^(J'\\,O|4v=\"q,@p@;\037[\"{!Dg*(\010\017WQ]:Q;$\004x]\032\035\003a#\"=;\005@&\003:;({>`y{?<X\025vb\032\037\"\"K8\025u[cb}\001;k', k\a/?xm1$\n_?Z\025t?\001,_?O=\001\003U,Rk<\\\027w]j@?J(5ybTb\006\0032@@4\002JP W,]EH|]\\G\e\003>.p/\022jP\f/4U)\006+\022(<{|.<|]]\032.,N,\016\000\036T,;\\49C>C[{b[v") { |str|
897
+ # h = RMail::Header.new
898
+ # h['header'] = str
899
+ # h.params('header')
900
+ # }
901
+
902
+ 0.upto(25) {
903
+ specials = '()<>@,;:\\"/[]?='
904
+ strings = [(0..rand(255)).collect {rand(127).chr}.to_s,
905
+ (0..255).collect {rand(255).chr}.to_s,
906
+ (0..255).collect {
907
+ r = rand(specials.length * 5)
908
+ case r
909
+ when 0 .. specials.length - 1
910
+ specials[r].chr
911
+ else
912
+ rand(127).chr
913
+ end
914
+ }.to_s ]
915
+ strings.each {|string|
916
+ assert_no_exception("failed for string #{string.inspect}") {
917
+ h = RMail::Header.new
918
+ h['header'] = string
919
+ params = h.params('header')
920
+ params.each { |name, value|
921
+ assert_kind_of(String, name)
922
+ assert(! ("" == name) )
923
+ assert_kind_of(String, value)
924
+ }
925
+ }
926
+ }
927
+ }
928
+ end
929
+
930
+ def test_param
931
+ begin
932
+ h = RMail::Header.new
933
+ assert_nil(h.param('bar', 'foo'))
934
+ assert_nil(h.param('bar', 'foo', nil))
935
+
936
+ default = "foo"
937
+ ignore = "ignore"
938
+ assert_same(default, h.param('bar', 'foo', default))
939
+ assert_same(default, h.param('bar', 'foo') { |field_name, param_name|
940
+ assert_equal('bar', field_name)
941
+ assert_equal('foo', param_name)
942
+ default
943
+ })
944
+ assert_same(default, h.param('bar', 'foo', ignore) {
945
+ default
946
+ })
947
+ end
948
+
949
+ begin
950
+ h = RMail::Header.new
951
+ h['Content-Disposition'] = 'attachment;
952
+ filename="delete_product_recover_flag.cmd"'
953
+ assert_equal('delete_product_recover_flag.cmd',
954
+ h.param('content-disposition',
955
+ 'filename'))
956
+ assert_nil(h.param('content-disposition', 'notthere'))
957
+ end
958
+
959
+ begin
960
+ h = RMail::Header.new
961
+ h['Content-Disposition'] = 'attachment;
962
+ filename="delete=_product=_recover;_flag;.cmd"'
963
+ assert_equal("delete=_product=_recover;_flag;.cmd",
964
+ h.param('content-disposition', 'filename'))
965
+ end
966
+
967
+ begin
968
+ h = RMail::Header.new
969
+ h['Content-Disposition'] = ' attachment ;
970
+ filename = " trailing_Whitespace.cmd " '
971
+ assert_equal(" trailing_Whitespace.cmd ",
972
+ h.param('content-disposition', 'filename'))
973
+ end
974
+ end
975
+
976
+ def test_date
977
+
978
+ begin
979
+ h = RMail::Header.new
980
+ h.add_raw("Date: Sat, 18 Jan 2003 21:00:09 -0700")
981
+ t = h.date
982
+ assert(!t.utc?)
983
+ t.utc
984
+ assert_equal([9, 0, 4, 19, 1, 2003, 0], t.to_a[0, 7])
985
+ assert_match(/Sun, 19 Jan 2003 04:00:09 [+-]0000/, t.rfc2822)
986
+ end
987
+
988
+ begin
989
+ h = RMail::Header.new
990
+ h.add_raw("Date: Sat,18 Jan 2003 02:04:27 +0100 (CET)")
991
+ t = h.date
992
+ assert(!t.utc?)
993
+ t.utc
994
+ assert_equal([27, 4, 1, 18, 1, 2003, 6, 18], t.to_a[0, 8])
995
+ assert_match(/Sat, 18 Jan 2003 01:04:27 [+-]0000/, t.rfc2822)
996
+ end
997
+
998
+ begin
999
+ h = RMail::Header.new
1000
+ # This one is bogus and can't even be parsed.
1001
+ h.add_raw("Date: 21/01/2002 09:29:33 Pacific Daylight Time")
1002
+ t = assert_no_exception {
1003
+ h.date
1004
+ }
1005
+ assert_nil(t)
1006
+ end
1007
+
1008
+ begin
1009
+ h = RMail::Header.new
1010
+ # This time is out of the range that can be represented by a
1011
+ # Time object.
1012
+ h.add_raw("Date: Sun, 14 Jun 2065 05:51:55 +0200")
1013
+ t = assert_no_exception {
1014
+ h.date
1015
+ }
1016
+ assert_nil(t)
1017
+ end
1018
+
1019
+ end
1020
+
1021
+ def test_date_eq
1022
+ h = RMail::Header.new
1023
+ t = Time.at(1042949885).utc
1024
+ h.date = t
1025
+ assert_match(/Sun, 19 Jan 2003 04:18:05 [+-]0000/, h['date'])
1026
+ end
1027
+
1028
+ def test_from
1029
+ begin
1030
+ h = RMail::Header.new
1031
+ h.add_raw('From: matt@example.net')
1032
+ a = h.from
1033
+ assert_kind_of(Array, a)
1034
+ assert_kind_of(RMail::Address::List, a)
1035
+ assert_equal(1, a.length)
1036
+ assert_kind_of(RMail::Address, a.first)
1037
+ assert_equal(RMail::Address.new("matt@example.net"), a.first)
1038
+ end
1039
+
1040
+ begin
1041
+ h = RMail::Header.new
1042
+ h.add_raw('From: Matt Armstrong <matt@example.net>,
1043
+ Bob Smith <bob@example.com>')
1044
+ a = h.from
1045
+ assert_kind_of(Array, a)
1046
+ assert_kind_of(RMail::Address::List, a)
1047
+ assert_equal(2, a.length)
1048
+ assert_kind_of(RMail::Address, a[0])
1049
+ assert_equal("matt@example.net", a[0].address)
1050
+ assert_equal("Matt Armstrong", a[0].display_name)
1051
+ assert_kind_of(RMail::Address, a[1])
1052
+ assert_equal("bob@example.com", a[1].address)
1053
+ assert_equal("Bob Smith", a[1].display_name)
1054
+ end
1055
+
1056
+ begin
1057
+ h = RMail::Header.new
1058
+ a = h.from
1059
+ assert_kind_of(Array, a)
1060
+ assert_kind_of(RMail::Address::List, a)
1061
+ assert_equal(0, a.length)
1062
+ assert_nil(h.from.first)
1063
+ end
1064
+ end
1065
+
1066
+ def common_test_address_list_header_assign(field_name)
1067
+ h = RMail::Header.new
1068
+
1069
+ get = field_name.downcase.gsub(/-/, '_')
1070
+ assign = get + '='
1071
+
1072
+ h.__send__("#{assign}", "bob@example.net")
1073
+ assert_equal(1, h.length)
1074
+ assert_equal("bob@example.net", h[field_name])
1075
+
1076
+ h[field_name] = "bob2@example.net"
1077
+ assert_equal(2, h.length)
1078
+ assert_equal("bob@example.net", h[field_name])
1079
+ assert_equal(["bob@example.net", "bob2@example.net"],
1080
+ h.fetch_all(field_name))
1081
+ assert_equal(["bob@example.net", "bob2@example.net"],
1082
+ h.__send__("#{get}"))
1083
+
1084
+ h.__send__("#{assign}", "sally@example.net")
1085
+ assert_equal(1, h.length)
1086
+ assert_equal("sally@example.net", h[field_name])
1087
+
1088
+ h.__send__("#{assign}", "Sally <sally@example.net>, bob@example.invalid (Bob)")
1089
+ assert_equal(1, h.length)
1090
+ assert_equal(2, h.__send__(get).length)
1091
+ assert_equal(%w{ sally bob },
1092
+ h.__send__(get).locals)
1093
+ assert_equal([ 'Sally', nil ],
1094
+ h.__send__(get).display_names)
1095
+ assert_equal([ 'Sally', 'Bob' ],
1096
+ h.__send__(get).names,
1097
+ "got wrong result for #names")
1098
+ assert_equal(%w{ example.net example.invalid },
1099
+ h.__send__(get).domains)
1100
+ assert_equal(%w{ sally@example.net bob@example.invalid },
1101
+ h.__send__(get).addresses)
1102
+ assert_equal([ "Sally <sally@example.net>", "bob@example.invalid (Bob)" ],
1103
+ h.__send__(get).format)
1104
+
1105
+ h.__send__("#{assign}", RMail::Address.new('Bill <bill@example.net>'))
1106
+ assert_equal(1, h.length)
1107
+ assert_equal(1, h.__send__(get).length)
1108
+ assert_equal(%w{ bill@example.net }, h.__send__(get).addresses)
1109
+ assert_equal('bill@example.net', h.__send__(get)[0].address)
1110
+ assert_equal('Bill', h.__send__(get)[0].display_name)
1111
+
1112
+ h.__send__("#{assign}", RMail::Address.parse('Bob <bob@example.net>, ' +
1113
+ 'Sally <sally@example.net>'))
1114
+ assert_equal(1, h.length)
1115
+ assert_equal(2, h.__send__(get).length)
1116
+ assert_equal(%w{ bob@example.net sally@example.net },
1117
+ h.__send__(get).addresses)
1118
+ assert_equal('bob@example.net', h.__send__(get)[0].address)
1119
+ assert_equal('Bob', h.__send__(get)[0].display_name)
1120
+ assert_equal('sally@example.net', h.__send__(get)[1].address)
1121
+ assert_equal('Sally', h.__send__(get)[1].display_name)
1122
+ end
1123
+
1124
+ def test_from_assign
1125
+ common_test_address_list_header_assign('From')
1126
+ end
1127
+
1128
+ def test_to_assign
1129
+ common_test_address_list_header_assign('To')
1130
+ end
1131
+
1132
+ def test_reply_cc_assign
1133
+ common_test_address_list_header_assign('Cc')
1134
+ end
1135
+
1136
+ def test_reply_bcc_assign
1137
+ common_test_address_list_header_assign('Bcc')
1138
+ end
1139
+
1140
+ def test_reply_to_assign
1141
+ common_test_address_list_header_assign('Reply-To')
1142
+ end
1143
+
1144
+ def test_message_id
1145
+ h = RMail::Header.new
1146
+ h.set('Message-Id', '<foo@bar>')
1147
+ assert_equal('<foo@bar>', h.message_id)
1148
+ end
1149
+
1150
+ def test_add_message_id
1151
+ h = RMail::Header.new
1152
+ h.add_message_id
1153
+
1154
+ a = RMail::Address.parse(h.message_id).first
1155
+ require 'socket'
1156
+ assert_equal(Socket.gethostname + '.invalid', a.domain)
1157
+ assert_equal('rubymail', a.local.split('.')[3])
1158
+ assert_equal('0', a.local.split('.')[2],
1159
+ "md5 data present for empty header")
1160
+ assert_match(/[a-z0-9]{5,6}/, a.local.split('.')[0])
1161
+ assert_match(/[a-z0-9]{5,6}/, a.local.split('.')[1])
1162
+
1163
+ h.to = "matt@lickey.com"
1164
+ h.delete('message-id')
1165
+ h.add_message_id
1166
+ a = RMail::Address.parse(h.message_id).first
1167
+ assert_equal('70bmbq38pc5q462kl4ikv0mcq', a.local.split('.')[2],
1168
+ "md5 hash wrong for header")
1169
+ end
1170
+
1171
+ def test_subject
1172
+ h = RMail::Header.new
1173
+ h['subject'] = 'hi mom'
1174
+ assert_equal('hi mom', h.subject)
1175
+ assert_equal('hi mom', h['subject'])
1176
+ h.subject = 'hi dad'
1177
+ assert_equal(1, h.length)
1178
+ assert_equal('hi dad', h['subject'])
1179
+ assert_equal('hi dad', h['Subject'])
1180
+ assert_equal("Subject: hi dad\n", h.to_s)
1181
+ end
1182
+
1183
+ def test_recipients
1184
+ %w{ to cc bcc }.each { |field_name|
1185
+ h = RMail::Header.new
1186
+ h[field_name] = 'matt@lickey.com'
1187
+ assert_equal([ 'matt@lickey.com' ], h.recipients )
1188
+ h[field_name] = 'bob@lickey.com'
1189
+ assert_equal([ 'matt@lickey.com', 'bob@lickey.com' ], h.recipients )
1190
+ }
1191
+
1192
+ h = RMail::Header.new
1193
+ h.to = [ 'bob@example.net', 'sally@example.net' ]
1194
+ h.cc = 'bill@example.net'
1195
+ h.bcc = 'samuel@example.net'
1196
+ assert_kind_of(RMail::Address::List, h.recipients)
1197
+ assert_equal([ 'bill@example.net',
1198
+ 'bob@example.net',
1199
+ 'sally@example.net',
1200
+ 'samuel@example.net' ], h.recipients.sort)
1201
+
1202
+ h = RMail::Header.new
1203
+ assert_kind_of(RMail::Address::List, h.recipients)
1204
+ assert_equal(0, h.recipients.length)
1205
+ end
1206
+
1207
+ end