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/runtests.rb
ADDED
@@ -0,0 +1,35 @@
|
|
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
|
+
fail "must run this script directly" unless __FILE__ == $0
|
29
|
+
path = File.expand_path(File.join(File.dirname($0), '..', 'lib'))
|
30
|
+
puts "Prepending #{path} to the $LOAD_PATH"
|
31
|
+
$LOAD_PATH.unshift(path) # get our stuff first
|
32
|
+
|
33
|
+
Dir['tests/test*.rb'].each {|f|
|
34
|
+
require f
|
35
|
+
}
|
@@ -0,0 +1,1192 @@
|
|
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
|
+
require 'tests/testbase'
|
29
|
+
require 'rmail/address'
|
30
|
+
|
31
|
+
class TestRMailAddress < TestBase
|
32
|
+
|
33
|
+
def domain_optional
|
34
|
+
# Set to true for tests that include addresses without a domain
|
35
|
+
# portion.
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_list
|
40
|
+
[:display_name, :name, :address, :comments,
|
41
|
+
:format, :domain, :local]
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate_method(object, method, *args)
|
45
|
+
assert(method_list.include?(method),
|
46
|
+
"#{method.inspect} not in #{method_list.inspect}")
|
47
|
+
assert_respond_to(method, object)
|
48
|
+
ret = nil
|
49
|
+
ret = object.send(method, *args)
|
50
|
+
if block_given?
|
51
|
+
yield(ret)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate_interface(address)
|
56
|
+
assert_instance_of(RMail::Address, address)
|
57
|
+
|
58
|
+
validate_method(address, :display_name) { |ret|
|
59
|
+
assert_instance_of(String, ret) unless ret.nil?
|
60
|
+
}
|
61
|
+
|
62
|
+
validate_method(address, :name) { |ret|
|
63
|
+
assert_instance_of(String, ret) unless ret.nil?
|
64
|
+
}
|
65
|
+
|
66
|
+
validate_method(address, :address) { |ret|
|
67
|
+
assert_instance_of(String, ret) unless ret.nil?
|
68
|
+
}
|
69
|
+
|
70
|
+
validate_method(address, :comments) { |ret|
|
71
|
+
unless ret.nil?
|
72
|
+
assert_instance_of(Array, ret)
|
73
|
+
ret.each { |comment|
|
74
|
+
assert_instance_of(String, comment)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
}
|
78
|
+
|
79
|
+
validate_method(address, :format) { |ret|
|
80
|
+
assert_instance_of(String, ret) unless ret.nil?
|
81
|
+
}
|
82
|
+
|
83
|
+
validate_method(address, :domain) { |ret|
|
84
|
+
assert_instance_of(String, ret) unless ret.nil?
|
85
|
+
}
|
86
|
+
|
87
|
+
validate_method(address, :local) { |ret|
|
88
|
+
assert_instance_of(String, ret) unless ret.nil?
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
def validate_case(testcase, debug = false)
|
93
|
+
begin
|
94
|
+
prev_debug = $DEBUG
|
95
|
+
$DEBUG = debug
|
96
|
+
results = RMail::Address.parse(testcase[0])
|
97
|
+
ensure
|
98
|
+
$DEBUG = prev_debug
|
99
|
+
end
|
100
|
+
assert_kind_of(Array, results)
|
101
|
+
assert_kind_of(RMail::Address::List, results)
|
102
|
+
results.each { |address|
|
103
|
+
validate_interface(address)
|
104
|
+
}
|
105
|
+
expected_results = testcase[1]
|
106
|
+
assert_instance_of(Array, expected_results)
|
107
|
+
assert_equal(expected_results.length, results.length,
|
108
|
+
"results array wrong length, got #{results.inspect}")
|
109
|
+
|
110
|
+
results.each_with_index { |address, i|
|
111
|
+
assert_instance_of(Hash, expected_results[i])
|
112
|
+
methods = method_list
|
113
|
+
expected_results[i].each { |method, expected|
|
114
|
+
validate_method(address, method) { |ret|
|
115
|
+
assert_equal(expected, ret,
|
116
|
+
"\nstring #{testcase[0].inspect}\naddr #{address.inspect}\nmethod #{method.inspect}\n")
|
117
|
+
}
|
118
|
+
methods.delete(method)
|
119
|
+
}
|
120
|
+
assert_equal(0, methods.length,
|
121
|
+
"test case did not test these methods #{methods.inspect}")
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_rfc_2822()
|
126
|
+
|
127
|
+
# The following are from RFC2822
|
128
|
+
validate_case\
|
129
|
+
['John Doe <jdoe@machine.example>',
|
130
|
+
[ { :name => 'John Doe',
|
131
|
+
:display_name => 'John Doe',
|
132
|
+
:address => 'jdoe@machine.example',
|
133
|
+
:comments => nil,
|
134
|
+
:domain => 'machine.example',
|
135
|
+
:local => 'jdoe',
|
136
|
+
:format => 'John Doe <jdoe@machine.example>' } ]]
|
137
|
+
|
138
|
+
validate_case\
|
139
|
+
[' Mary Smith <mary@example.net>',
|
140
|
+
[ { :name => 'Mary Smith',
|
141
|
+
:display_name => 'Mary Smith',
|
142
|
+
:address => 'mary@example.net',
|
143
|
+
:comments => nil,
|
144
|
+
:domain => 'example.net',
|
145
|
+
:local => 'mary',
|
146
|
+
:format => 'Mary Smith <mary@example.net>' } ]]
|
147
|
+
|
148
|
+
validate_case\
|
149
|
+
['"Joe Q. Public" <john.q.public@example.com>',
|
150
|
+
[ { :name => 'Joe Q. Public',
|
151
|
+
:display_name => 'Joe Q. Public',
|
152
|
+
:address => 'john.q.public@example.com',
|
153
|
+
:comments => nil,
|
154
|
+
:domain => 'example.com',
|
155
|
+
:local => 'john.q.public',
|
156
|
+
:format => '"Joe Q. Public" <john.q.public@example.com>' } ]]
|
157
|
+
|
158
|
+
validate_case\
|
159
|
+
['Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>',
|
160
|
+
[ { :name => 'Mary Smith',
|
161
|
+
:display_name => 'Mary Smith',
|
162
|
+
:address => 'mary@x.test',
|
163
|
+
:comments => nil,
|
164
|
+
:domain => 'x.test',
|
165
|
+
:local => 'mary',
|
166
|
+
:format => 'Mary Smith <mary@x.test>' },
|
167
|
+
{ :name => nil,
|
168
|
+
:display_name => nil,
|
169
|
+
:address => 'jdoe@example.org',
|
170
|
+
:comments => nil,
|
171
|
+
:domain => 'example.org',
|
172
|
+
:local => 'jdoe',
|
173
|
+
:format => 'jdoe@example.org' },
|
174
|
+
{ :name => 'Who?',
|
175
|
+
:display_name => 'Who?',
|
176
|
+
:address => 'one@y.test',
|
177
|
+
:comments => nil,
|
178
|
+
:domain => 'y.test',
|
179
|
+
:local => 'one',
|
180
|
+
:format => 'Who? <one@y.test>' } ]]
|
181
|
+
|
182
|
+
validate_case\
|
183
|
+
['<boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>',
|
184
|
+
[ { :name => nil,
|
185
|
+
:display_name => nil,
|
186
|
+
:address => 'boss@nil.test',
|
187
|
+
:comments => nil,
|
188
|
+
:domain => 'nil.test',
|
189
|
+
:local => 'boss',
|
190
|
+
:format => 'boss@nil.test' },
|
191
|
+
{ :name => 'Giant; "Big" Box',
|
192
|
+
:display_name => 'Giant; "Big" Box',
|
193
|
+
:address => 'sysservices@example.net',
|
194
|
+
:comments => nil,
|
195
|
+
:domain => 'example.net',
|
196
|
+
:local => 'sysservices',
|
197
|
+
:format => '"Giant; \"Big\" Box" <sysservices@example.net>' }
|
198
|
+
] ]
|
199
|
+
|
200
|
+
validate_case\
|
201
|
+
['A Group:Chris Jones <c@a.test>,joe@where.test,John <jdoe@one.test>;',
|
202
|
+
[ { :name => 'Chris Jones',
|
203
|
+
:display_name => 'Chris Jones',
|
204
|
+
:address => 'c@a.test',
|
205
|
+
:comments => nil,
|
206
|
+
:domain => 'a.test',
|
207
|
+
:local => 'c',
|
208
|
+
:format => 'Chris Jones <c@a.test>' },
|
209
|
+
{ :name => nil,
|
210
|
+
:display_name => nil,
|
211
|
+
:address => 'joe@where.test',
|
212
|
+
:comments => nil,
|
213
|
+
:domain => 'where.test',
|
214
|
+
:local => 'joe',
|
215
|
+
:format => 'joe@where.test' },
|
216
|
+
{ :name => 'John',
|
217
|
+
:display_name => 'John',
|
218
|
+
:address => 'jdoe@one.test',
|
219
|
+
:comments => nil,
|
220
|
+
:domain => 'one.test',
|
221
|
+
:local => 'jdoe',
|
222
|
+
:format => 'John <jdoe@one.test>' }
|
223
|
+
] ]
|
224
|
+
|
225
|
+
validate_case\
|
226
|
+
['Undisclosed recipients:;',
|
227
|
+
[] ]
|
228
|
+
|
229
|
+
validate_case\
|
230
|
+
['undisclosed recipients: ;',
|
231
|
+
[] ]
|
232
|
+
|
233
|
+
validate_case\
|
234
|
+
['"Mary Smith: Personal Account" <smith@home.example> ',
|
235
|
+
[ { :name => 'Mary Smith: Personal Account',
|
236
|
+
:display_name => 'Mary Smith: Personal Account',
|
237
|
+
:address => 'smith@home.example',
|
238
|
+
:comments => nil,
|
239
|
+
:domain => 'home.example',
|
240
|
+
:local => 'smith',
|
241
|
+
:format => '"Mary Smith: Personal Account" <smith@home.example>' }
|
242
|
+
] ]
|
243
|
+
|
244
|
+
validate_case\
|
245
|
+
['Pete(A wonderful \) chap) <pete(his account)@silly.test(his host)>',
|
246
|
+
[ { :name => 'Pete',
|
247
|
+
:display_name => 'Pete',
|
248
|
+
:address => 'pete@silly.test',
|
249
|
+
:comments => ['A wonderful ) chap', 'his account', 'his host'],
|
250
|
+
:domain => 'silly.test',
|
251
|
+
:local => 'pete',
|
252
|
+
:format => 'Pete <pete@silly.test> (A wonderful \) chap) (his account) (his host)' }
|
253
|
+
] ]
|
254
|
+
|
255
|
+
validate_case\
|
256
|
+
['A Group:a@b.c,d@e.f;',
|
257
|
+
[ { :name => nil, :display_name => nil, :comments => nil,
|
258
|
+
:local => 'a', :domain => 'b.c', :format => 'a@b.c',
|
259
|
+
:address => 'a@b.c' },
|
260
|
+
{ :name => nil, :display_name => nil, :comments => nil,
|
261
|
+
:local => 'd', :domain => 'e.f', :format => 'd@e.f',
|
262
|
+
:address => 'd@e.f' } ] ]
|
263
|
+
|
264
|
+
validate_case\
|
265
|
+
["A Group(Some people)\r\n :Chris Jones <c@(Chris's host.)public.example>,\r\n joe@example.org",
|
266
|
+
[ { :name => 'Chris Jones',
|
267
|
+
:display_name => 'Chris Jones',
|
268
|
+
:address => 'c@public.example',
|
269
|
+
:comments => ['Chris\'s host.'],
|
270
|
+
:domain => 'public.example',
|
271
|
+
:local => 'c',
|
272
|
+
:format => 'Chris Jones <c@public.example> (Chris\'s host.)' } ] ]
|
273
|
+
|
274
|
+
validate_case\
|
275
|
+
["A Group(Some people)\r\n :Chris Jones <c@(Chris's host.)public.example>,\r\n joe@example.org;",
|
276
|
+
[ { :name => 'Chris Jones',
|
277
|
+
:display_name => 'Chris Jones',
|
278
|
+
:address => 'c@public.example',
|
279
|
+
:comments => ['Chris\'s host.'],
|
280
|
+
:domain => 'public.example',
|
281
|
+
:local => 'c',
|
282
|
+
:format => 'Chris Jones <c@public.example> (Chris\'s host.)' },
|
283
|
+
{ :name => nil,
|
284
|
+
:display_name => nil,
|
285
|
+
:address => 'joe@example.org',
|
286
|
+
:comments => nil,
|
287
|
+
:domain => 'example.org',
|
288
|
+
:local => 'joe',
|
289
|
+
:format => 'joe@example.org' }
|
290
|
+
] ]
|
291
|
+
|
292
|
+
validate_case\
|
293
|
+
['(Empty list)(start)Undisclosed recipients :(nobody(that I know)) ;',
|
294
|
+
[] ]
|
295
|
+
|
296
|
+
# Note, the space is lost after the Q. because we always convert
|
297
|
+
# word . word into "word.word" for output. To preserve the space,
|
298
|
+
# the guy should quote his name.
|
299
|
+
# FIXME: maybe fix this behavior?
|
300
|
+
validate_case\
|
301
|
+
['Joe Q. Public <john.q.public@example.com>',
|
302
|
+
[ { :name => 'Joe Q.Public',
|
303
|
+
:display_name => 'Joe Q.Public',
|
304
|
+
:address => 'john.q.public@example.com',
|
305
|
+
:comments => nil,
|
306
|
+
:domain => 'example.com',
|
307
|
+
:local => 'john.q.public',
|
308
|
+
:format => '"Joe Q.Public" <john.q.public@example.com>' } ] ]
|
309
|
+
|
310
|
+
# FIXME: maybe expect "B.J.Major" <bjbear71@example.net>
|
311
|
+
validate_case\
|
312
|
+
['B.J. Major <bjbear71@example.net>',
|
313
|
+
[ { :name => 'B.J.Major',
|
314
|
+
:display_name => 'B.J.Major',
|
315
|
+
:address => 'bjbear71@example.net',
|
316
|
+
:comments => nil,
|
317
|
+
:domain => 'example.net',
|
318
|
+
:local => 'bjbear71',
|
319
|
+
:format => '"B.J.Major" <bjbear71@example.net>' } ] ]
|
320
|
+
|
321
|
+
validate_case\
|
322
|
+
['jdoe@test . example',
|
323
|
+
[ { :name => nil,
|
324
|
+
:display_name => nil,
|
325
|
+
:address => 'jdoe@test.example',
|
326
|
+
:comments => nil,
|
327
|
+
:domain => 'test.example',
|
328
|
+
:local => 'jdoe',
|
329
|
+
:format => 'jdoe@test.example' } ] ]
|
330
|
+
|
331
|
+
validate_case\
|
332
|
+
['Mary Smith <@machine.tld:mary@example.net>, , jdoe@test . example',
|
333
|
+
[ { :name => 'Mary Smith',
|
334
|
+
:display_name => 'Mary Smith',
|
335
|
+
:address => 'mary@example.net',
|
336
|
+
:comments => nil,
|
337
|
+
:domain => 'example.net',
|
338
|
+
:local => 'mary',
|
339
|
+
:format => 'Mary Smith <mary@example.net>' },
|
340
|
+
{ :name => nil,
|
341
|
+
:display_name => nil,
|
342
|
+
:address => 'jdoe@test.example',
|
343
|
+
:comments => nil,
|
344
|
+
:domain => 'test.example',
|
345
|
+
:local => 'jdoe',
|
346
|
+
:format => 'jdoe@test.example' } ] ]
|
347
|
+
|
348
|
+
validate_case\
|
349
|
+
['John Doe <jdoe@machine(comment). example>',
|
350
|
+
[ { :name => 'John Doe',
|
351
|
+
:display_name => 'John Doe',
|
352
|
+
:address => 'jdoe@machine.example',
|
353
|
+
:comments => ['comment'],
|
354
|
+
:domain => 'machine.example',
|
355
|
+
:local => 'jdoe',
|
356
|
+
:format => 'John Doe <jdoe@machine.example> (comment)' } ] ]
|
357
|
+
|
358
|
+
validate_case\
|
359
|
+
["Mary Smith\n\r \n <mary@example.net>",
|
360
|
+
[ { :name => 'Mary Smith',
|
361
|
+
:display_name => 'Mary Smith',
|
362
|
+
:address => 'mary@example.net',
|
363
|
+
:comments => nil,
|
364
|
+
:domain => 'example.net',
|
365
|
+
:local => 'mary',
|
366
|
+
:format => 'Mary Smith <mary@example.net>' } ] ]
|
367
|
+
end
|
368
|
+
|
369
|
+
# Tests stolen from majordomoII
|
370
|
+
def test_majordomoII
|
371
|
+
validate_case\
|
372
|
+
["tibbs@uh.edu (Homey ( j (\(\() t ) Tibbs)",
|
373
|
+
[ { :name => 'Homey ( j ((() t ) Tibbs',
|
374
|
+
:display_name => nil,
|
375
|
+
:address => 'tibbs@uh.edu',
|
376
|
+
:domain => 'uh.edu',
|
377
|
+
:local => 'tibbs',
|
378
|
+
:comments => [ 'Homey ( j ((() t ) Tibbs' ],
|
379
|
+
:format => 'tibbs@uh.edu (Homey \( j \(\(\(\) t \) Tibbs)' } ] ]
|
380
|
+
|
381
|
+
validate_case\
|
382
|
+
['"tibbs@home"@hpc.uh.edu (JLT )',
|
383
|
+
[ { :name => 'JLT ',
|
384
|
+
:address => 'tibbs@home@hpc.uh.edu',
|
385
|
+
:display_name => nil,
|
386
|
+
:domain => 'hpc.uh.edu',
|
387
|
+
:local => 'tibbs@home',
|
388
|
+
:comments => [ 'JLT ' ],
|
389
|
+
:format => '"tibbs@home"@hpc.uh.edu (JLT )' } ] ]
|
390
|
+
|
391
|
+
validate_case\
|
392
|
+
['tibbs@[129.7.3.5]',
|
393
|
+
[ { :name => nil,
|
394
|
+
:display_name => nil,
|
395
|
+
:domain => '[129.7.3.5]',
|
396
|
+
:local => 'tibbs',
|
397
|
+
:comments => nil,
|
398
|
+
:address => 'tibbs@[129.7.3.5]',
|
399
|
+
:format => '<tibbs@[129.7.3.5]>' } ] ]
|
400
|
+
|
401
|
+
validate_case\
|
402
|
+
['A_Foriegner%across.the.pond@relay1.uu.net',
|
403
|
+
[ { :name => nil,
|
404
|
+
:display_name => nil,
|
405
|
+
:domain => 'relay1.uu.net',
|
406
|
+
:local => 'A_Foriegner%across.the.pond',
|
407
|
+
:comments => nil,
|
408
|
+
:address => 'A_Foriegner%across.the.pond@relay1.uu.net',
|
409
|
+
:format => 'A_Foriegner%across.the.pond@relay1.uu.net' } ] ]
|
410
|
+
|
411
|
+
validate_case\
|
412
|
+
['"Jason @ Tibbitts" <tibbs@uh.edu>',
|
413
|
+
[ { :name => 'Jason @ Tibbitts',
|
414
|
+
:display_name => 'Jason @ Tibbitts',
|
415
|
+
:domain => 'uh.edu',
|
416
|
+
:local => 'tibbs',
|
417
|
+
:comments => nil,
|
418
|
+
:address => 'tibbs@uh.edu',
|
419
|
+
:format => '"Jason @ Tibbitts" <tibbs@uh.edu>' } ] ]
|
420
|
+
|
421
|
+
# Majordomo II parses all of these with an error. We have deleted
|
422
|
+
# some of the tests since when they are actually legal.
|
423
|
+
validate_case ['tibbs@uh.edu Jason Tibbitts', [] ]
|
424
|
+
validate_case ['@uh.edu', [] ] # Can't start with @
|
425
|
+
validate_case ['J <tibbs>', [] ] # Not FQDN
|
426
|
+
validate_case ['<tibbs Da Man', [] ] # Unbalanced
|
427
|
+
validate_case ['Jason <tibbs>>', [] ] # Unbalanced
|
428
|
+
validate_case ['tibbs, nobody', [] ] # Multiple addresses not allowed
|
429
|
+
validate_case ['tibbs@.hpc', [] ] # Illegal @.
|
430
|
+
validate_case ['<a@b>@c', [] ] # @ illegal in phrase
|
431
|
+
validate_case ['<a@>', [] ] # No hostname
|
432
|
+
validate_case ['<a@b>.abc', [] ] # >. illegal
|
433
|
+
validate_case ['<a@b> blah <d@e>', [] ] # Two routes illegal
|
434
|
+
validate_case ['<tibbs<tib@a>@hpc.uh.edu>', [] ] # Nested routes illegal
|
435
|
+
validate_case ['[<tibbs@hpc.uh.edu>]', [] ] # Enclosed in []
|
436
|
+
validate_case ['<a@b.cd> Me [blurfl] U', [] ] # Domain literals illegal in comment
|
437
|
+
validate_case ['A B @ C <a@b.c>', [] ] # @ not legal in comment
|
438
|
+
validate_case ['blah . tibbs@', [] ] # Unquoted . not legal in comment
|
439
|
+
validate_case ['tibbs@hpc.uh.edu.', [] ] # Address ends with a dot
|
440
|
+
validate_case ['sina.hpc.uh.edu', [] ] # No local-part@
|
441
|
+
validate_case ['tibbs@@math.uh.edu', [] ] # Two @s next to each other
|
442
|
+
validate_case ['tibbs@math@uh.edu', [] ] # Two @s, not next to each other
|
443
|
+
end
|
444
|
+
|
445
|
+
def test_mailtools_suite()
|
446
|
+
|
447
|
+
#
|
448
|
+
# The following are from the Perl MailTools module version 1.40
|
449
|
+
#
|
450
|
+
validate_case\
|
451
|
+
['"Joe & J. Harvey" <ddd @Org>, JJV @ BBN',
|
452
|
+
[ { :name => 'Joe & J. Harvey',
|
453
|
+
:display_name => 'Joe & J. Harvey',
|
454
|
+
:address => 'ddd@Org',
|
455
|
+
:comments => nil,
|
456
|
+
:domain => 'Org',
|
457
|
+
:local => 'ddd',
|
458
|
+
:format => '"Joe & J. Harvey" <ddd@Org>' },
|
459
|
+
{ :name => nil,
|
460
|
+
:display_name => nil,
|
461
|
+
:address => 'JJV@BBN',
|
462
|
+
:comments => nil,
|
463
|
+
:domain => 'BBN',
|
464
|
+
:local => 'JJV',
|
465
|
+
:format => 'JJV@BBN' } ] ]
|
466
|
+
|
467
|
+
validate_case\
|
468
|
+
['"spickett@tiac.net" <Sean.Pickett@zork.tiac.net>',
|
469
|
+
[ { :name => 'spickett@tiac.net',
|
470
|
+
:display_name => 'spickett@tiac.net',
|
471
|
+
:address => 'Sean.Pickett@zork.tiac.net',
|
472
|
+
:comments => nil,
|
473
|
+
:domain => 'zork.tiac.net',
|
474
|
+
:local => 'Sean.Pickett',
|
475
|
+
:format => '"spickett@tiac.net" <Sean.Pickett@zork.tiac.net>' } ] ]
|
476
|
+
|
477
|
+
validate_case\
|
478
|
+
['rls@intgp8.ih.att.com (-Schieve,R.L.)',
|
479
|
+
[ { :name => '-Schieve,R.L.',
|
480
|
+
:display_name => nil,
|
481
|
+
:address => 'rls@intgp8.ih.att.com',
|
482
|
+
:comments => ['-Schieve,R.L.'],
|
483
|
+
:domain => 'intgp8.ih.att.com',
|
484
|
+
:local => 'rls',
|
485
|
+
:format => 'rls@intgp8.ih.att.com (-Schieve,R.L.)' } ] ]
|
486
|
+
|
487
|
+
validate_case\
|
488
|
+
['jrh%cup.portal.com@portal.unix.portal.com',
|
489
|
+
[ { :name => nil,
|
490
|
+
:display_name => nil,
|
491
|
+
:address => 'jrh%cup.portal.com@portal.unix.portal.com',
|
492
|
+
:comments => nil,
|
493
|
+
:domain => 'portal.unix.portal.com',
|
494
|
+
:local => 'jrh%cup.portal.com',
|
495
|
+
:format => 'jrh%cup.portal.com@portal.unix.portal.com' } ] ]
|
496
|
+
|
497
|
+
validate_case\
|
498
|
+
['astrachan@austlcm.sps.mot.com (\'paul astrachan/xvt3\')',
|
499
|
+
[ { :name => '\'paul astrachan/xvt3\'',
|
500
|
+
:display_name => nil,
|
501
|
+
:address => 'astrachan@austlcm.sps.mot.com',
|
502
|
+
:comments => ['\'paul astrachan/xvt3\''],
|
503
|
+
:domain => 'austlcm.sps.mot.com',
|
504
|
+
:local => 'astrachan',
|
505
|
+
:format =>
|
506
|
+
'astrachan@austlcm.sps.mot.com (\'paul astrachan/xvt3\')' } ] ]
|
507
|
+
|
508
|
+
validate_case\
|
509
|
+
['TWINE57%SDELVB.decnet@SNYBUF.CS.SNYBUF.EDU (JAMES R. TWINE - THE NERD)',
|
510
|
+
[ { :name => 'JAMES R. TWINE - THE NERD',
|
511
|
+
:display_name => nil,
|
512
|
+
:address => 'TWINE57%SDELVB.decnet@SNYBUF.CS.SNYBUF.EDU',
|
513
|
+
:comments => ['JAMES R. TWINE - THE NERD'],
|
514
|
+
:domain => 'SNYBUF.CS.SNYBUF.EDU',
|
515
|
+
:local => 'TWINE57%SDELVB.decnet',
|
516
|
+
:format =>
|
517
|
+
'TWINE57%SDELVB.decnet@SNYBUF.CS.SNYBUF.EDU (JAMES R. TWINE - THE NERD)'} ] ]
|
518
|
+
|
519
|
+
validate_case\
|
520
|
+
['David Apfelbaum <da0g+@andrew.cmu.edu>',
|
521
|
+
[ { :name => 'David Apfelbaum',
|
522
|
+
:display_name => 'David Apfelbaum',
|
523
|
+
:address => 'da0g+@andrew.cmu.edu',
|
524
|
+
:comments => nil,
|
525
|
+
:domain => 'andrew.cmu.edu',
|
526
|
+
:local => 'da0g+',
|
527
|
+
:format => 'David Apfelbaum <da0g+@andrew.cmu.edu>' } ] ]
|
528
|
+
|
529
|
+
validate_case\
|
530
|
+
['"JAMES R. TWINE - THE NERD" <TWINE57%SDELVB%SNYDELVA.bitnet@CUNYVM.CUNY.EDU>',
|
531
|
+
[ { :name => 'JAMES R. TWINE - THE NERD',
|
532
|
+
:display_name => 'JAMES R. TWINE - THE NERD',
|
533
|
+
:address => 'TWINE57%SDELVB%SNYDELVA.bitnet@CUNYVM.CUNY.EDU',
|
534
|
+
:comments => nil,
|
535
|
+
:domain => 'CUNYVM.CUNY.EDU',
|
536
|
+
:local => 'TWINE57%SDELVB%SNYDELVA.bitnet',
|
537
|
+
:format => '"JAMES R. TWINE - THE NERD" <TWINE57%SDELVB%SNYDELVA.bitnet@CUNYVM.CUNY.EDU>' } ] ]
|
538
|
+
|
539
|
+
validate_case\
|
540
|
+
['/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk',
|
541
|
+
[ { :name => nil,
|
542
|
+
:display_name => nil,
|
543
|
+
:address => '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk',
|
544
|
+
:comments => nil,
|
545
|
+
:domain => 'mhs-relay.ac.uk',
|
546
|
+
:local => '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/',
|
547
|
+
:format => '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk' } ] ]
|
548
|
+
|
549
|
+
validate_case\
|
550
|
+
['"Stephen Burke, Liverpool" <BURKE@vxdsya.desy.de>',
|
551
|
+
[ { :name => 'Stephen Burke, Liverpool',
|
552
|
+
:display_name => 'Stephen Burke, Liverpool',
|
553
|
+
:address => 'BURKE@vxdsya.desy.de',
|
554
|
+
:comments => nil,
|
555
|
+
:domain => 'vxdsya.desy.de',
|
556
|
+
:local => 'BURKE',
|
557
|
+
:format => '"Stephen Burke, Liverpool" <BURKE@vxdsya.desy.de>' } ] ]
|
558
|
+
|
559
|
+
validate_case\
|
560
|
+
['The Newcastle Info-Server <info-admin@newcastle.ac.uk>',
|
561
|
+
[ { :name => 'The Newcastle Info-Server',
|
562
|
+
:display_name => 'The Newcastle Info-Server',
|
563
|
+
:address => 'info-admin@newcastle.ac.uk',
|
564
|
+
:comments => nil,
|
565
|
+
:domain => 'newcastle.ac.uk',
|
566
|
+
:local => 'info-admin',
|
567
|
+
:format => 'The Newcastle Info-Server <info-admin@newcastle.ac.uk>'
|
568
|
+
} ] ]
|
569
|
+
|
570
|
+
validate_case\
|
571
|
+
['Suba.Peddada@eng.sun.com (Suba Peddada [CONTRACTOR])',
|
572
|
+
[ { :name => 'Suba Peddada [CONTRACTOR]',
|
573
|
+
:display_name => nil,
|
574
|
+
:address => 'Suba.Peddada@eng.sun.com',
|
575
|
+
:comments => ['Suba Peddada [CONTRACTOR]'],
|
576
|
+
:domain => 'eng.sun.com',
|
577
|
+
:local => 'Suba.Peddada',
|
578
|
+
:format => 'Suba.Peddada@eng.sun.com (Suba Peddada [CONTRACTOR])'
|
579
|
+
} ] ]
|
580
|
+
|
581
|
+
validate_case\
|
582
|
+
['Paul Manser (0032 memo) <a906187@tiuk.ti.com>',
|
583
|
+
[ { :name => 'Paul Manser',
|
584
|
+
:display_name => 'Paul Manser',
|
585
|
+
:address => 'a906187@tiuk.ti.com',
|
586
|
+
:comments => ['0032 memo'],
|
587
|
+
:domain => 'tiuk.ti.com',
|
588
|
+
:local => 'a906187',
|
589
|
+
:format => 'Paul Manser <a906187@tiuk.ti.com> (0032 memo)' } ] ]
|
590
|
+
|
591
|
+
validate_case\
|
592
|
+
['"gregg (g.) woodcock" <woodcock@bnr.ca>',
|
593
|
+
[ { :name => 'gregg (g.) woodcock',
|
594
|
+
:display_name => 'gregg (g.) woodcock',
|
595
|
+
:address => 'woodcock@bnr.ca',
|
596
|
+
:comments => nil,
|
597
|
+
:domain => 'bnr.ca',
|
598
|
+
:local => 'woodcock',
|
599
|
+
:format => '"gregg (g.) woodcock" <woodcock@bnr.ca>' } ] ]
|
600
|
+
|
601
|
+
validate_case\
|
602
|
+
['Graham.Barr@tiuk.ti.com',
|
603
|
+
[ { :name => nil,
|
604
|
+
:display_name => nil,
|
605
|
+
:address => 'Graham.Barr@tiuk.ti.com',
|
606
|
+
:comments => nil,
|
607
|
+
:domain => 'tiuk.ti.com',
|
608
|
+
:local => 'Graham.Barr',
|
609
|
+
:format => 'Graham.Barr@tiuk.ti.com' } ] ]
|
610
|
+
|
611
|
+
if domain_optional
|
612
|
+
validate_case\
|
613
|
+
['a909937 (Graham Barr (0004 bodg))',
|
614
|
+
[ { :name => 'Graham Barr (0004 bodg)',
|
615
|
+
:display_name => nil,
|
616
|
+
:address => 'a909937',
|
617
|
+
:comments => ['Graham Barr (0004 bodg)'],
|
618
|
+
:domain => nil,
|
619
|
+
:local => 'a909937',
|
620
|
+
:format => 'a909937 (Graham Barr \(0004 bodg\))' } ] ]
|
621
|
+
end
|
622
|
+
|
623
|
+
validate_case\
|
624
|
+
['david d `zoo\' zuhn <zoo@aggregate.com>',
|
625
|
+
[ { :name => 'david d `zoo\' zuhn',
|
626
|
+
:display_name => 'david d `zoo\' zuhn',
|
627
|
+
:address => 'zoo@aggregate.com',
|
628
|
+
:comments => nil,
|
629
|
+
:domain => 'aggregate.com',
|
630
|
+
:local => 'zoo',
|
631
|
+
:format => 'david d `zoo\' zuhn <zoo@aggregate.com>' } ] ]
|
632
|
+
|
633
|
+
validate_case\
|
634
|
+
['(foo@bar.com (foobar), ned@foo.com (nedfoo) ) <kevin@goess.org>',
|
635
|
+
[ { :name => 'foo@bar.com (foobar), ned@foo.com (nedfoo) ',
|
636
|
+
:display_name => nil,
|
637
|
+
:address => 'kevin@goess.org',
|
638
|
+
:comments => ['foo@bar.com (foobar), ned@foo.com (nedfoo) '],
|
639
|
+
:domain => 'goess.org',
|
640
|
+
:local => 'kevin',
|
641
|
+
:format =>
|
642
|
+
'kevin@goess.org (foo@bar.com \(foobar\), ned@foo.com \(nedfoo\) )'
|
643
|
+
} ]]
|
644
|
+
end
|
645
|
+
|
646
|
+
def test_rfc_822
|
647
|
+
|
648
|
+
validate_case\
|
649
|
+
['":sysmail"@ Some-Group. Some-Org, Muhammed.(I am the greatest) Ali @(the)Vegas.WBA',
|
650
|
+
[ { :name => nil,
|
651
|
+
:display_name => nil,
|
652
|
+
:address => ':sysmail@Some-Group.Some-Org',
|
653
|
+
:comments => nil,
|
654
|
+
:domain => 'Some-Group.Some-Org',
|
655
|
+
:local => ':sysmail',
|
656
|
+
:format => '":sysmail"@Some-Group.Some-Org' },
|
657
|
+
{ :name => 'the',
|
658
|
+
:display_name => nil,
|
659
|
+
:address => 'Muhammed.Ali@Vegas.WBA',
|
660
|
+
:comments => ['I am the greatest', 'the'],
|
661
|
+
:domain => 'Vegas.WBA',
|
662
|
+
:local => 'Muhammed.Ali',
|
663
|
+
:format => 'Muhammed.Ali@Vegas.WBA (I am the greatest) (the)' } ] ]
|
664
|
+
end
|
665
|
+
|
666
|
+
def test_misc_addresses()
|
667
|
+
|
668
|
+
# Make sure that parsing empty stuff works
|
669
|
+
assert_equal([], RMail::Address.parse(nil))
|
670
|
+
assert_equal([], RMail::Address.parse(""))
|
671
|
+
assert_equal([], RMail::Address.parse(" "))
|
672
|
+
assert_equal([], RMail::Address.parse("\t"))
|
673
|
+
assert_equal([], RMail::Address.parse("\n"))
|
674
|
+
assert_equal([], RMail::Address.parse("\r"))
|
675
|
+
|
676
|
+
# From a bogus header I saw sent to ruby-talk
|
677
|
+
validate_case([' ruby-talk@ruby-lang.org (ruby-talk ML),
|
678
|
+
<ruby-talk ML <ruby-talk@ruby-lang.org>>',
|
679
|
+
[ { :name => 'ruby-talk ML',
|
680
|
+
:display_name => nil,
|
681
|
+
:comments => [ 'ruby-talk ML' ],
|
682
|
+
:domain => 'ruby-lang.org',
|
683
|
+
:local => 'ruby-talk',
|
684
|
+
:address => 'ruby-talk@ruby-lang.org',
|
685
|
+
:format => 'ruby-talk@ruby-lang.org (ruby-talk ML)' }
|
686
|
+
] ])
|
687
|
+
|
688
|
+
# From Python address parsing bug list. This is valid according
|
689
|
+
# to RFC2822.
|
690
|
+
validate_case(['Amazon.com <delivers-news2@amazon.com>',
|
691
|
+
[ { :name => 'Amazon.com',
|
692
|
+
:display_name => 'Amazon.com',
|
693
|
+
:address => 'delivers-news2@amazon.com',
|
694
|
+
:comments => nil,
|
695
|
+
:domain => 'amazon.com',
|
696
|
+
:local => 'delivers-news2',
|
697
|
+
:format => '"Amazon.com" <delivers-news2@amazon.com>'
|
698
|
+
} ] ])
|
699
|
+
|
700
|
+
validate_case\
|
701
|
+
["\r\n Amazon \r . \n com \t < delivers-news2@amazon.com > \n ",
|
702
|
+
[ { :name => 'Amazon.com',
|
703
|
+
:display_name => 'Amazon.com',
|
704
|
+
:address => 'delivers-news2@amazon.com',
|
705
|
+
:comments => nil,
|
706
|
+
:domain => 'amazon.com',
|
707
|
+
:local => 'delivers-news2',
|
708
|
+
:format => '"Amazon.com" <delivers-news2@amazon.com>'
|
709
|
+
} ] ]
|
710
|
+
|
711
|
+
# From postfix-users@postfix.org
|
712
|
+
# Date: Tue, 13 Nov 2001 10:58:23 -0800
|
713
|
+
# Subject: Apparent bug in strict_rfc821_envelopes (Snapshot-20010714)
|
714
|
+
validate_case\
|
715
|
+
['"mailto:rfc"@monkeys.test',
|
716
|
+
[ { :name => nil,
|
717
|
+
:display_name => nil,
|
718
|
+
:address => 'mailto:rfc@monkeys.test',
|
719
|
+
:comments => nil,
|
720
|
+
:domain => 'monkeys.test',
|
721
|
+
:local => 'mailto:rfc',
|
722
|
+
:format => '"mailto:rfc"@monkeys.test' } ] ]
|
723
|
+
|
724
|
+
# An unquoted mailto:rfc will end up being detected as an invalid
|
725
|
+
# group display name.
|
726
|
+
validate_case ['mailto:rfc@monkeys.test', [] ]
|
727
|
+
|
728
|
+
# From gnu.emacs.help
|
729
|
+
# Date: 24 Nov 2001 15:37:23 -0500
|
730
|
+
validate_case\
|
731
|
+
['"Stefan Monnier <foo@acm.com>" <monnier+gnu.emacs.help/news/@flint.cs.yale.edu>',
|
732
|
+
[ { :name => 'Stefan Monnier <foo@acm.com>',
|
733
|
+
:display_name => 'Stefan Monnier <foo@acm.com>',
|
734
|
+
:address => 'monnier+gnu.emacs.help/news/@flint.cs.yale.edu',
|
735
|
+
:comments => nil,
|
736
|
+
:domain => 'flint.cs.yale.edu',
|
737
|
+
:local => 'monnier+gnu.emacs.help/news/',
|
738
|
+
:format => '"Stefan Monnier <foo@acm.com>" <monnier+gnu.emacs.help/news/@flint.cs.yale.edu>' } ] ]
|
739
|
+
|
740
|
+
{ :name => nil,
|
741
|
+
:display_name => nil,
|
742
|
+
:address => nil,
|
743
|
+
:comments => nil,
|
744
|
+
:domain => nil,
|
745
|
+
:local => nil,
|
746
|
+
:format => nil }
|
747
|
+
|
748
|
+
validate_case\
|
749
|
+
['"foo:" . bar@somewhere.test',
|
750
|
+
[ { :name => nil,
|
751
|
+
:display_name => nil,
|
752
|
+
:address => 'foo:.bar@somewhere.test',
|
753
|
+
:comments => nil,
|
754
|
+
:domain => 'somewhere.test',
|
755
|
+
:local => 'foo:.bar',
|
756
|
+
:format => '"foo:.bar"@somewhere.test' } ] ]
|
757
|
+
|
758
|
+
validate_case\
|
759
|
+
['Some Dude <"foo:" . bar@somewhere.test>',
|
760
|
+
[ { :name => 'Some Dude',
|
761
|
+
:display_name => 'Some Dude',
|
762
|
+
:address => 'foo:.bar@somewhere.test',
|
763
|
+
:comments => nil,
|
764
|
+
:domain => 'somewhere.test',
|
765
|
+
:local => 'foo:.bar',
|
766
|
+
:format => 'Some Dude <"foo:.bar"@somewhere.test>' } ] ]
|
767
|
+
|
768
|
+
validate_case\
|
769
|
+
['"q\uo\ted"@example.com, Luke Skywalker <"use"."the.force"@space.test>',
|
770
|
+
[ { :name => nil,
|
771
|
+
:display_name => nil,
|
772
|
+
:address => 'quoted@example.com',
|
773
|
+
:comments => nil,
|
774
|
+
:domain => 'example.com',
|
775
|
+
:local => 'quoted',
|
776
|
+
:format => 'quoted@example.com' },
|
777
|
+
{ :name => 'Luke Skywalker',
|
778
|
+
:display_name => 'Luke Skywalker',
|
779
|
+
:address => 'use.the.force@space.test',
|
780
|
+
:comments => nil,
|
781
|
+
:domain => 'space.test',
|
782
|
+
:local => 'use.the.force',
|
783
|
+
:format => 'Luke Skywalker <use.the.force@space.test>' } ] ]
|
784
|
+
|
785
|
+
validate_case\
|
786
|
+
['Erik =?ISO-8859-1?Q?B=E5gfors?= <erik@example.net>',
|
787
|
+
[ { :name => 'Erik =?ISO-8859-1?Q?B=E5gfors?=',
|
788
|
+
:display_name => 'Erik =?ISO-8859-1?Q?B=E5gfors?=',
|
789
|
+
:address => 'erik@example.net',
|
790
|
+
:comments => nil,
|
791
|
+
:domain => 'example.net',
|
792
|
+
:local => 'erik',
|
793
|
+
:format => 'Erik =?ISO-8859-1?Q?B=E5gfors?= <erik@example.net>'
|
794
|
+
} ] ]
|
795
|
+
end
|
796
|
+
|
797
|
+
def test_invalid_addresses()
|
798
|
+
# The display name isn't encoded -- bad, but we parse it.
|
799
|
+
validate_case\
|
800
|
+
["\322\315\322 \312\353\363\341 <bar@foo.invalid>",
|
801
|
+
[ { :name => "\322\315\322 \312\353\363\341",
|
802
|
+
:display_name => "\322\315\322 \312\353\363\341",
|
803
|
+
:address => 'bar@foo.invalid',
|
804
|
+
:comments => nil,
|
805
|
+
:domain => 'foo.invalid',
|
806
|
+
:local => 'bar',
|
807
|
+
:format => "\"\322\315\322 \312\353\363\341\" <bar@foo.invalid>",
|
808
|
+
} ] ]
|
809
|
+
end
|
810
|
+
|
811
|
+
def test_domain_literal
|
812
|
+
|
813
|
+
validate_case\
|
814
|
+
['test@[domain]',
|
815
|
+
[ { :name => nil,
|
816
|
+
:display_name => nil,
|
817
|
+
:address => 'test@[domain]',
|
818
|
+
:comments => nil,
|
819
|
+
:domain => '[domain]',
|
820
|
+
:local => 'test',
|
821
|
+
:format => '<test@[domain]>' } ] ]
|
822
|
+
|
823
|
+
validate_case\
|
824
|
+
['<@[obsdomain]:test@[domain]>',
|
825
|
+
[ { :name => nil,
|
826
|
+
:display_name => nil,
|
827
|
+
:address => 'test@[domain]',
|
828
|
+
:comments => nil,
|
829
|
+
:domain => '[domain]',
|
830
|
+
:local => 'test',
|
831
|
+
:format => '<test@[domain]>' } ] ]
|
832
|
+
|
833
|
+
validate_case\
|
834
|
+
['<@[ob\]sd\\\\omain]:test@[dom\]ai\\\\n]>',
|
835
|
+
[ { :name => nil,
|
836
|
+
:display_name => nil,
|
837
|
+
:address => 'test@[dom]ai\\n]',
|
838
|
+
:comments => nil,
|
839
|
+
:domain => '[dom]ai\\n]',
|
840
|
+
:local => 'test',
|
841
|
+
:format => '<test@[dom\]ai\\\\n]>' } ] ]
|
842
|
+
|
843
|
+
validate_case\
|
844
|
+
["Bob \r<@machine.tld \r,\n,,, @[obsdomain],@foo\t:\ntest @ [domain]>",
|
845
|
+
[ { :name => 'Bob',
|
846
|
+
:display_name => 'Bob',
|
847
|
+
:address => 'test@[domain]',
|
848
|
+
:comments => nil,
|
849
|
+
:domain => '[domain]',
|
850
|
+
:local => 'test',
|
851
|
+
:format => 'Bob <test@[domain]>' } ] ]
|
852
|
+
end
|
853
|
+
|
854
|
+
def test_exhaustive()
|
855
|
+
|
856
|
+
# We don't test every alphanumeric in atext -- assume that if a, m
|
857
|
+
# and z work, they all will.
|
858
|
+
atext = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a +
|
859
|
+
'!#$%&\'*+-/=?^_`{|}~'.split(//) #/
|
860
|
+
boring = ('b'..'l').to_a + ('n'..'o').to_a +
|
861
|
+
('p'..'y').to_a + ('B'..'L').to_a + ('N'..'O').to_a +
|
862
|
+
('P'..'Y').to_a + ('1'..'4').to_a + ('6'..'8').to_a
|
863
|
+
|
864
|
+
(atext - boring).each {|ch|
|
865
|
+
validate_case(["#{ch} <#{ch}@test>",
|
866
|
+
[ { :name => ch,
|
867
|
+
:display_name => ch,
|
868
|
+
:address => "#{ch}@test",
|
869
|
+
:comments => nil,
|
870
|
+
:domain => 'test',
|
871
|
+
:local => ch,
|
872
|
+
:format => ch + ' <' + ch + '@test>' } ] ])
|
873
|
+
}
|
874
|
+
|
875
|
+
validate_case([atext.join('') + ' <' + atext.join('') + '@test>',
|
876
|
+
[ { :name => atext.join(''),
|
877
|
+
:display_name => atext.join(''),
|
878
|
+
:address => atext.join('') + '@test',
|
879
|
+
:comments => nil,
|
880
|
+
:domain => 'test',
|
881
|
+
:local => atext.join(''),
|
882
|
+
:format => atext.join('') + ' <' + atext.join('') +
|
883
|
+
'@test>' } ] ])
|
884
|
+
|
885
|
+
ascii = (0..127).collect {|i| i.chr}
|
886
|
+
whitespace = ["\r", "\n", ' ', "\t"]
|
887
|
+
qtext = ascii - (whitespace + ['"', '\\'])
|
888
|
+
ctext = ascii - (whitespace + ['(', ')', '\\'])
|
889
|
+
dtext = ascii - (whitespace + ['[', ']', '\\'])
|
890
|
+
|
891
|
+
(qtext - atext).each {|ch|
|
892
|
+
validate_case(["\"#{ch}\" <\"#{ch}\"@test>",
|
893
|
+
[ { :name => ch,
|
894
|
+
:display_name => ch,
|
895
|
+
:address => "#{ch}@test",
|
896
|
+
:comments => nil,
|
897
|
+
:domain => 'test',
|
898
|
+
:local => "#{ch}",
|
899
|
+
:format => "\"#{ch}\" <\"#{ch}\"@test>" } ] ])
|
900
|
+
}
|
901
|
+
['"', "\\"].each {|ch|
|
902
|
+
validate_case(["\"\\#{ch}\" <\"\\#{ch}\"@test>",
|
903
|
+
[ { :name => ch,
|
904
|
+
:display_name => ch,
|
905
|
+
:address => ch + '@test',
|
906
|
+
:comments => nil,
|
907
|
+
:domain => 'test',
|
908
|
+
:local => ch,
|
909
|
+
:format => "\"\\#{ch}\" <\"\\#{ch}\"@test>" } ] ])
|
910
|
+
}
|
911
|
+
|
912
|
+
(ctext - boring).each {|ch|
|
913
|
+
validate_case(["bob@test (#{ch})",
|
914
|
+
[ { :name => ch,
|
915
|
+
:display_name => nil,
|
916
|
+
:address => 'bob@test',
|
917
|
+
:comments => ["#{ch}"],
|
918
|
+
:domain => 'test',
|
919
|
+
:local => 'bob',
|
920
|
+
:format => "bob@test (#{ch})" } ] ])
|
921
|
+
validate_case(["bob@test (\\#{ch})",
|
922
|
+
[ { :name => ch,
|
923
|
+
:display_name => nil,
|
924
|
+
:address => 'bob@test',
|
925
|
+
:comments => ["#{ch}"],
|
926
|
+
:domain => 'test',
|
927
|
+
:local => 'bob',
|
928
|
+
:format => "bob@test (#{ch})" } ] ])
|
929
|
+
}
|
930
|
+
[')', '(', '\\'].each {|ch|
|
931
|
+
validate_case(["bob@test (\\#{ch})",
|
932
|
+
[ { :name => ch,
|
933
|
+
:display_name => nil,
|
934
|
+
:address => 'bob@test',
|
935
|
+
:comments => ["#{ch}"],
|
936
|
+
:domain => 'test',
|
937
|
+
:local => 'bob',
|
938
|
+
:format => 'bob@test (\\' + ch + ')' } ] ])
|
939
|
+
}
|
940
|
+
|
941
|
+
(dtext - boring).each {|ch|
|
942
|
+
validate_case(["test@[\\#{ch}] (Sam)",
|
943
|
+
[ { :name => "Sam",
|
944
|
+
:display_name => nil,
|
945
|
+
:address => 'test@[' + ch + ']',
|
946
|
+
:comments => ["Sam"],
|
947
|
+
:domain => '[' + ch + ']',
|
948
|
+
:local => 'test',
|
949
|
+
:format => "<test@[#{ch}]> (Sam)" } ] ] )
|
950
|
+
validate_case(["Sally <test@[\\#{ch}]>",
|
951
|
+
[ { :name => "Sally",
|
952
|
+
:display_name => "Sally",
|
953
|
+
:address => 'test@[' + ch + ']',
|
954
|
+
:comments => nil,
|
955
|
+
:domain => '[' + ch + ']',
|
956
|
+
:local => 'test',
|
957
|
+
:format => "Sally <test@[#{ch}]>" } ] ] )
|
958
|
+
}
|
959
|
+
|
960
|
+
validate_case(["test@[" + (dtext - boring).join('') + "]",
|
961
|
+
[ { :name => nil,
|
962
|
+
:display_name => nil,
|
963
|
+
:address => 'test@[' + (dtext - boring).join('') + "]",
|
964
|
+
:comments => nil,
|
965
|
+
:domain => '[' + (dtext - boring).join('') + ']',
|
966
|
+
:local => 'test',
|
967
|
+
:format => "<test@[" +
|
968
|
+
(dtext - boring).join('') + "]>" } ] ])
|
969
|
+
validate_case(["Bob <test@[" + (dtext - boring).join('') + "]>",
|
970
|
+
[ { :name => "Bob",
|
971
|
+
:display_name => "Bob",
|
972
|
+
:address => 'test@[' + (dtext - boring).join('') + "]",
|
973
|
+
:comments => nil,
|
974
|
+
:domain => '[' + (dtext - boring).join('') + ']',
|
975
|
+
:local => 'test',
|
976
|
+
:format => "Bob <test@[" +
|
977
|
+
(dtext - boring).join('') + "]>" } ] ])
|
978
|
+
end
|
979
|
+
|
980
|
+
def test_out_of_spec()
|
981
|
+
|
982
|
+
validate_case ['bodg fred@tiuk.ti.com', [] ]
|
983
|
+
validate_case ['(comment) bodg fred@example.net, matt@example.com',
|
984
|
+
[ { :name => nil, :display_name => nil, :comments => nil,
|
985
|
+
:address => 'matt@example.com',
|
986
|
+
:domain => 'example.com',
|
987
|
+
:local => 'matt',
|
988
|
+
:format => 'matt@example.com' } ] ]
|
989
|
+
|
990
|
+
validate_case ['<Investor Alert@example.com>', [] ]
|
991
|
+
|
992
|
+
validate_case ['"" <bob@example.com>',
|
993
|
+
[ { :name => nil,
|
994
|
+
:display_name => nil,
|
995
|
+
:address => 'bob@example.com',
|
996
|
+
:comments => nil,
|
997
|
+
:domain => 'example.com',
|
998
|
+
:local => 'bob',
|
999
|
+
:format => 'bob@example.com' } ] ]
|
1000
|
+
|
1001
|
+
validate_case\
|
1002
|
+
['"" <""@example.com>',
|
1003
|
+
[ ] ]
|
1004
|
+
|
1005
|
+
validate_case\
|
1006
|
+
['@example.com',
|
1007
|
+
[ ] ]
|
1008
|
+
|
1009
|
+
if domain_optional
|
1010
|
+
validate_case\
|
1011
|
+
['bob',
|
1012
|
+
[ { :name => nil,
|
1013
|
+
:display_name => nil,
|
1014
|
+
:address => 'bob',
|
1015
|
+
:comments => nil,
|
1016
|
+
:domain => nil,
|
1017
|
+
:local => 'bob',
|
1018
|
+
:format => 'bob' } ] ]
|
1019
|
+
|
1020
|
+
validate_case\
|
1021
|
+
['bob,sally, sam',
|
1022
|
+
[ { :name => nil,
|
1023
|
+
:display_name => nil,
|
1024
|
+
:address => 'bob',
|
1025
|
+
:comments => nil,
|
1026
|
+
:domain => nil,
|
1027
|
+
:local => 'bob',
|
1028
|
+
:format => 'bob' },
|
1029
|
+
{ :name => nil,
|
1030
|
+
:display_name => nil,
|
1031
|
+
:address => 'sally',
|
1032
|
+
:comments => nil,
|
1033
|
+
:domain => nil,
|
1034
|
+
:local => 'sally',
|
1035
|
+
:format => 'sally' },
|
1036
|
+
{ :name => nil,
|
1037
|
+
:display_name => nil,
|
1038
|
+
:address => 'sam',
|
1039
|
+
:comments => nil,
|
1040
|
+
:domain => nil,
|
1041
|
+
:local => 'sam',
|
1042
|
+
:format => 'sam' }] ]
|
1043
|
+
else
|
1044
|
+
validate_case [ 'bob', [] ]
|
1045
|
+
validate_case [ 'Bobby, sally,sam', [] ]
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
validate_case(['Undisclosed <>', []])
|
1049
|
+
validate_case(['"Mensagem Automatica do Terra" <>', []])
|
1050
|
+
|
1051
|
+
validate_case(["\177", []])
|
1052
|
+
validate_case(["\177\177\177", []])
|
1053
|
+
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
def test_random_strings
|
1057
|
+
|
1058
|
+
# These random strings have generated exceptions before, so test
|
1059
|
+
# them forever.
|
1060
|
+
RMail::Address.parse("j732[S\031\022\000\fuh\003Ye<2psd\005#1L=Hw*c\0247\006\aE\fXJ\026;\026\032zAAgpCFq+\010")
|
1061
|
+
RMail::Address.parse("\016o7=\024d^\001|h<,#\026~(<oS\005 f<u\022u+4\"\020d \023h\004)\036\016\023YY0\n]W]'\025S\t\035")
|
1062
|
+
RMail::Address.parse("<")
|
1063
|
+
RMail::Address.parse("J.:")
|
1064
|
+
# find_shortest_failure("\276\231J.^\351I:\2564") { |s|
|
1065
|
+
# RMail::Address.parse(s)
|
1066
|
+
# }
|
1067
|
+
|
1068
|
+
0.upto(25) {
|
1069
|
+
specials = ',;\\()":@<>'
|
1070
|
+
strings = [(0..rand(255)).collect {rand(127).chr}.to_s,
|
1071
|
+
(0..255).collect {rand(255).chr}.to_s,
|
1072
|
+
(0..255).collect {
|
1073
|
+
r = rand(specials.length * 5)
|
1074
|
+
case r
|
1075
|
+
when 0 .. specials.length - 1
|
1076
|
+
specials[r].chr
|
1077
|
+
else
|
1078
|
+
rand(127).chr
|
1079
|
+
end
|
1080
|
+
}.to_s ]
|
1081
|
+
strings.each {|string|
|
1082
|
+
assert_no_exception("failed for string #{string.inspect}") {
|
1083
|
+
addrs = RMail::Address.parse(string)
|
1084
|
+
addrs.each {|address|
|
1085
|
+
method_list.each {|method|
|
1086
|
+
address.send(method)
|
1087
|
+
}
|
1088
|
+
}
|
1089
|
+
}
|
1090
|
+
}
|
1091
|
+
}
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
def test_initialize
|
1095
|
+
addr = RMail::Address.new
|
1096
|
+
assert_instance_of(RMail::Address, addr)
|
1097
|
+
|
1098
|
+
addr = RMail::Address.new("Bob Smith (Joe Bob) <bobs@example.com>")
|
1099
|
+
assert_instance_of(RMail::Address, addr)
|
1100
|
+
assert_equal("Bob Smith", addr.display_name)
|
1101
|
+
assert_equal("Bob Smith", addr.name)
|
1102
|
+
assert_equal("example.com", addr.domain)
|
1103
|
+
assert_equal("bobs", addr.local)
|
1104
|
+
|
1105
|
+
addr = RMail::Address.new("Bob Smith (Joe Bob) <bobs@example.com>" +
|
1106
|
+
", Sally Joe (Hi Babe) <sallyj@test.example>")
|
1107
|
+
assert_instance_of(RMail::Address, addr)
|
1108
|
+
assert_equal("Bob Smith", addr.display_name)
|
1109
|
+
assert_equal("Bob Smith", addr.name)
|
1110
|
+
assert_equal("example.com", addr.domain)
|
1111
|
+
assert_equal("bobs", addr.local)
|
1112
|
+
|
1113
|
+
addr = RMail::Address.new("\177\177")
|
1114
|
+
assert_instance_of(RMail::Address, addr)
|
1115
|
+
assert_equal(nil, addr.display_name)
|
1116
|
+
assert_equal(nil, addr.name)
|
1117
|
+
assert_equal(nil, addr.domain)
|
1118
|
+
assert_equal(nil, addr.local)
|
1119
|
+
|
1120
|
+
e = assert_exception(ArgumentError) {
|
1121
|
+
RMail::Address.new(["bob"])
|
1122
|
+
}
|
1123
|
+
e = assert_exception(ArgumentError) {
|
1124
|
+
RMail::Address.new(Object.new)
|
1125
|
+
}
|
1126
|
+
e = assert_exception(ArgumentError) {
|
1127
|
+
RMail::Address.new(Hash.new)
|
1128
|
+
}
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
def test_comments
|
1132
|
+
a = RMail::Address.new
|
1133
|
+
assert_nil(a.comments)
|
1134
|
+
a.comments = [ 'foo', 'bar' ]
|
1135
|
+
assert_equal([ 'foo', 'bar' ], a.comments)
|
1136
|
+
a.comments = 'foo'
|
1137
|
+
assert_equal([ 'foo' ], a.comments)
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
def test_rmail_address_compare
|
1141
|
+
a1 = RMail::Address.new
|
1142
|
+
a2 = RMail::Address.new
|
1143
|
+
|
1144
|
+
# Make sure it works on uninitialized addresses
|
1145
|
+
assert_equal(0, a1 <=> a2)
|
1146
|
+
assert_equal(a1, a2)
|
1147
|
+
|
1148
|
+
# Display name and comments make no difference
|
1149
|
+
a1.display_name = 'foo'
|
1150
|
+
a1.comments = 'bar'
|
1151
|
+
assert_equal(0, a1 <=> a2)
|
1152
|
+
assert_equal(a1, a2)
|
1153
|
+
|
1154
|
+
# a1 < a2
|
1155
|
+
a1 = RMail::Address.new("Zeus <bob@example.com>")
|
1156
|
+
a2 = RMail::Address.new("sally@example.com")
|
1157
|
+
assert(a1 < a2)
|
1158
|
+
assert(a1 != a2)
|
1159
|
+
|
1160
|
+
# Type coercion
|
1161
|
+
assert(a1 < "zorton@example.com")
|
1162
|
+
assert(a1 > ".")
|
1163
|
+
assert(a1 == "bob@example.com")
|
1164
|
+
end
|
1165
|
+
|
1166
|
+
def test_rmail_address_eql?
|
1167
|
+
a1 = RMail::Address.new
|
1168
|
+
a2 = RMail::Address.new
|
1169
|
+
|
1170
|
+
# Make sure it works on uninitialized addresses
|
1171
|
+
assert(a1.eql?(a2))
|
1172
|
+
|
1173
|
+
# Display name and comments make no difference
|
1174
|
+
a1.display_name = 'foo'
|
1175
|
+
a1.comments = 'bar'
|
1176
|
+
assert(a1.eql?(a2))
|
1177
|
+
|
1178
|
+
a1 = RMail::Address.new("Zeus <bob@example.com>")
|
1179
|
+
assert_exception(TypeError) {
|
1180
|
+
a1.eql?("bob@eaxample.com")
|
1181
|
+
}
|
1182
|
+
end
|
1183
|
+
|
1184
|
+
def test_rmail_address_hash
|
1185
|
+
assert_no_exception {
|
1186
|
+
RMail::Address.new.hash
|
1187
|
+
}
|
1188
|
+
a1 = RMail::Address.new("Zeus <bob@example.com>")
|
1189
|
+
assert_equal(a1.hash, "bob@example.com".hash)
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
end
|