rmail-sup 1.0.1

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