rmail 0.17

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 (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