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.
- data/NEWS +309 -0
- data/NOTES +14 -0
- data/README +83 -0
- data/THANKS +25 -0
- data/TODO +112 -0
- data/guide/Intro.txt +122 -0
- data/guide/MIME.txt +6 -0
- data/guide/TableOfContents.txt +13 -0
- data/install.rb +1023 -0
- data/lib/rmail.rb +50 -0
- data/lib/rmail/address.rb +829 -0
- data/lib/rmail/header.rb +987 -0
- data/lib/rmail/mailbox.rb +62 -0
- data/lib/rmail/mailbox/mboxreader.rb +182 -0
- data/lib/rmail/message.rb +201 -0
- data/lib/rmail/parser.rb +412 -0
- data/lib/rmail/parser/multipart.rb +217 -0
- data/lib/rmail/parser/pushbackreader.rb +173 -0
- data/lib/rmail/serialize.rb +190 -0
- data/lib/rmail/utils.rb +59 -0
- data/rmail.gemspec +17 -0
- data/tests/addrgrammar.txt +113 -0
- data/tests/data/mbox.odd +4 -0
- data/tests/data/mbox.simple +8 -0
- data/tests/data/multipart/data.1 +5 -0
- data/tests/data/multipart/data.10 +1 -0
- data/tests/data/multipart/data.11 +9 -0
- data/tests/data/multipart/data.12 +9 -0
- data/tests/data/multipart/data.13 +3 -0
- data/tests/data/multipart/data.14 +3 -0
- data/tests/data/multipart/data.15 +3 -0
- data/tests/data/multipart/data.16 +3 -0
- data/tests/data/multipart/data.17 +0 -0
- data/tests/data/multipart/data.2 +5 -0
- data/tests/data/multipart/data.3 +2 -0
- data/tests/data/multipart/data.4 +3 -0
- data/tests/data/multipart/data.5 +1 -0
- data/tests/data/multipart/data.6 +2 -0
- data/tests/data/multipart/data.7 +3 -0
- data/tests/data/multipart/data.8 +5 -0
- data/tests/data/multipart/data.9 +4 -0
- data/tests/data/parser.badmime1 +4 -0
- data/tests/data/parser.badmime2 +6 -0
- data/tests/data/parser.nested-multipart +75 -0
- data/tests/data/parser.nested-simple +12 -0
- data/tests/data/parser.nested-simple2 +16 -0
- data/tests/data/parser.nested-simple3 +21 -0
- data/tests/data/parser.rfc822 +65 -0
- data/tests/data/parser.simple-mime +24 -0
- data/tests/data/parser/multipart.1 +8 -0
- data/tests/data/parser/multipart.10 +4 -0
- data/tests/data/parser/multipart.11 +12 -0
- data/tests/data/parser/multipart.12 +12 -0
- data/tests/data/parser/multipart.13 +6 -0
- data/tests/data/parser/multipart.14 +6 -0
- data/tests/data/parser/multipart.15 +6 -0
- data/tests/data/parser/multipart.16 +6 -0
- data/tests/data/parser/multipart.2 +8 -0
- data/tests/data/parser/multipart.3 +5 -0
- data/tests/data/parser/multipart.4 +6 -0
- data/tests/data/parser/multipart.5 +4 -0
- data/tests/data/parser/multipart.6 +5 -0
- data/tests/data/parser/multipart.7 +6 -0
- data/tests/data/parser/multipart.8 +8 -0
- data/tests/data/parser/multipart.9 +7 -0
- data/tests/data/transparency/absolute.1 +5 -0
- data/tests/data/transparency/absolute.2 +1 -0
- data/tests/data/transparency/absolute.3 +2 -0
- data/tests/data/transparency/absolute.4 +3 -0
- data/tests/data/transparency/absolute.5 +4 -0
- data/tests/data/transparency/absolute.6 +49 -0
- data/tests/data/transparency/message.1 +73 -0
- data/tests/data/transparency/message.2 +34 -0
- data/tests/data/transparency/message.3 +63 -0
- data/tests/data/transparency/message.4 +5 -0
- data/tests/data/transparency/message.5 +15 -0
- data/tests/data/transparency/message.6 +1185 -0
- data/tests/runtests.rb +35 -0
- data/tests/testaddress.rb +1192 -0
- data/tests/testbase.rb +207 -0
- data/tests/testheader.rb +1207 -0
- data/tests/testmailbox.rb +47 -0
- data/tests/testmboxreader.rb +161 -0
- data/tests/testmessage.rb +257 -0
- data/tests/testparser.rb +634 -0
- data/tests/testparsermultipart.rb +205 -0
- data/tests/testpushbackreader.rb +40 -0
- data/tests/testserialize.rb +264 -0
- data/tests/testtestbase.rb +112 -0
- data/tests/testtranspparency.rb +105 -0
- metadata +143 -0
data/tests/testbase.rb
ADDED
@@ -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
|
data/tests/testheader.rb
ADDED
@@ -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
|