mime 0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -43,6 +43,16 @@ module MIME
43
43
  # standards compliant message.
44
44
  #++
45
45
 
46
+ # FIXME writing directly to body VS setting body with a MediaType gives an
47
+ # imbalance of "\r\n". Setting body directly with string requires a CRLF
48
+ # prepended, but not the case for TextMedia for instance. So where do we
49
+ # handle this? Perhaps HeaderContainer#to_s should append a CRLF, or
50
+ # self#body should detect String and automatically prepend CRLF??? Then we
51
+ # remove the CRLF here between the headers and body.
52
+ #
53
+ # Also, TextMedia adds the Content-ID and Content-Type headers, which we
54
+ # don't get if body is set directly with String. Does this matter?
55
+
46
56
  "#{headers}\r\n#{body}\r\n"
47
57
  end
48
58
 
@@ -0,0 +1,18 @@
1
+ version = File.read('./lib/mime.rb')[/VERSION = '(.*)'/, 1]
2
+
3
+ Gem::Specification.new('mime', version) do |s|
4
+ s.author = 'Clint Pachl'
5
+ s.email = 'pachl@ecentryx.com'
6
+ s.homepage = 'http://ecentryx.com/gems/mime'
7
+ s.license = 'ISC'
8
+ s.summary = 'Multipurpose Internet Mail Extensions (MIME) Library'
9
+ s.description = <<-EOF
10
+ A library for building RFC compliant Multipurpose Internet Mail Extensions
11
+ (MIME) messages. It can be used to construct standardized MIME messages for use
12
+ in client/server communications, such as Internet mail or HTTP
13
+ multipart/form-data transactions.
14
+ EOF
15
+ s.files = Dir['README.rdoc', 'Rakefile', 'mime.gemspec',
16
+ 'lib/**/*.rb', 'test/**/*']
17
+ s.test_files = Dir['test/*.rb']
18
+ end
@@ -1,8 +1,8 @@
1
- Message-ID: <350015069@1033007998>
2
1
  Date: Wed, 29 Oct 2008 22:02:00 -0700
3
- MIME-Version: 1.0 (Ruby MIME v0.1)
2
+ Message-ID: <350015069@1033007998>
3
+ MIME-Version: 1.0 (Ruby MIME v0.2.0)
4
4
  Content-ID: <10330079680.971971651113797>
5
- Content-Transfer-Encoding: binary
6
5
  Content-Type: application/octet-stream
6
+ Content-Transfer-Encoding: binary
7
7
 
8
- 011000100110100101101110011000010111001001111001
8
+ 0110000101110101011001000110100101101111
@@ -1,8 +1,8 @@
1
- Message-ID: <738362674@978907908>
2
1
  Date: Wed, 29 Oct 2008 22:06:46 -0700
3
- MIME-Version: 1.0 (Ruby MIME v0.1)
2
+ Message-ID: <738362674@978907908>
3
+ MIME-Version: 1.0 (Ruby MIME v0.2.0)
4
4
  Content-ID: <9789078880.11546613041526>
5
- Content-Transfer-Encoding: binary
6
5
  Content-Type: audio/midi
6
+ Content-Transfer-Encoding: binary
7
7
 
8
8
  0110000101110101011001000110100101101111
File without changes
Binary file
@@ -1,17 +1,15 @@
1
- Content-ID: <9825632980.129140062591039>
2
- Content-Type: multipart/alternative; boundary=Boundary_9825632980.209951487532625
1
+ Content-ID: <154873488180000.3045551269054866>
2
+ Content-Type: multipart/alternative; boundary=Boundary_154873488180000.5284747660488839
3
3
 
4
- --Boundary_9825632980.209951487532625
5
- Content-ID: <9825630380.420138704080548>
6
- Content-Type: text/plain; charset=us-ascii
4
+ --Boundary_154873488180000.5284747660488839
5
+ Content-ID: <154873488189000.6392244491224042>
6
+ Content-Type: text/enhanced; charset=us-ascii
7
7
 
8
8
  *Header*
9
- message
10
-
11
- --Boundary_9825632980.209951487532625
12
- Content-ID: <9825630480.371191475053649>
9
+ message
10
+ --Boundary_154873488180000.5284747660488839
11
+ Content-ID: <154873488185800.3424043482513621>
13
12
  Content-Type: text/html; charset=iso-8859-1
14
13
 
15
- <html><body><h1>Header</h1><p>message</p></body></html>
16
-
17
- --Boundary_9825632980.209951487532625--
14
+ <html><body><h1>Header</h1><p>message</p></body></html>
15
+ --Boundary_154873488180000.5284747660488839--
@@ -1,22 +1,33 @@
1
- Content-ID: <10552388980.162896129188505>
2
- Content-Type: multipart/form-data; boundary=Boundary_10552388980.858426568801724
1
+ Content-ID: <88135231713600.7894413004791365>
2
+ Content-Type: multipart/form-data; boundary=Boundary_88135231713600.3996846921776409
3
3
 
4
- --Boundary_10552388980.858426568801724
5
- Content-ID: <10552388580.731954240756742>
6
- Content-Disposition: form-data; name="txt3"
7
- Content-Type: text/html
4
+ --Boundary_88135231713600.3996846921776409
5
+ Content-ID: <88135231717000.5720607746781624>
6
+ Content-Type: text/xml
7
+ Content-Disposition: form-data; name="xml"
8
8
 
9
- <html>
10
- <body>
11
- <h1>Sample HTML File</h1>
12
- <p>this is the body</p>
13
- </body>
14
- </html>
9
+ <media_types abstract="true">
10
+ <discrete_media_types abstract="true">
11
+ <application_media></application_media>
12
+ <audio_media></audio_media>
13
+ <image_media></image_media>
14
+ <text_media></text_media>
15
+ <video_media></video_media>
16
+ </discrete_media_types>
17
+ <composite_media_types abstract="true">
18
+ <multipart_media abstract="true">
19
+ <form_data></form_data>
20
+ <alternative></alternative>
21
+ </multipart>
22
+ <message_media>
23
+ </message_media>
24
+ </composite>
25
+ </media_types>
15
26
 
16
- --Boundary_10552388980.858426568801724
17
- Content-ID: <10552388580.731954240756742>
18
- Content-Disposition: form-data; name="txt3"
27
+ --Boundary_88135231713600.3996846921776409
28
+ Content-ID: <88135231721400.4415016053712104>
19
29
  Content-Type: text/html
30
+ Content-Disposition: form-data; name="htm"
20
31
 
21
32
  <html>
22
33
  <body>
@@ -25,16 +36,10 @@ Content-Type: text/html
25
36
  </body>
26
37
  </html>
27
38
 
28
- --Boundary_10552388980.858426568801724
29
- Content-ID: <10552385980.313922062472258>
30
- Content-Disposition: form-data; name="txt2"
31
- Content-Type: text/enhanced
32
-
33
- this is t2
34
- --Boundary_10552388980.858426568801724
35
- Content-ID: <10552385480.358570542235564>
36
- Content-Disposition: form-data; name="txt1"
39
+ --Boundary_88135231713600.3996846921776409
40
+ Content-ID: <88135231725400.11623307734175536>
37
41
  Content-Type: text/plain; charset=us-ascii
42
+ Content-Disposition: form-data; name="txt"
38
43
 
39
- this is t1
40
- --Boundary_10552388980.858426568801724--
44
+ text body
45
+ --Boundary_88135231713600.3996846921776409--
@@ -1,9 +1,11 @@
1
- Cc: bossman@domain.com <Head Honcho>
1
+ Date: Tue, 17 Dec 2013 04:54:56 -0700
2
+ Message-ID: <776432154@10297424291820>
3
+ MIME-Version: 1.0 (Ruby MIME v0.0.0)
4
+ To: John <john@example.com>, paul@example.com, Mary <mary@example.com>
5
+ Cc: boss@example.com <Head Honcho>
6
+ From: jane@example.com
2
7
  Subject: This is an important email
3
- Message-ID: <474040392@1043863700>
4
- From: person4@domain.com
5
- To: Mary <person3@domain.com>, person2@domain.com, Harry <person1@domain.com>
6
- Date: Mon, 27 Oct 2008 07:08:50 -0700
7
- MIME-Version: 1.0 (Ruby MIME v0.1)
8
+ Content-ID: <102975158103800.7998663631497803>
9
+ Content-Type: text/plain; charset=us-ascii
8
10
 
9
- This is the all important email body
11
+ Hello, world!
@@ -1,6 +1,6 @@
1
- Message-ID: <357114433@1021851988>
2
1
  Date: Wed, 29 Oct 2008 14:55:34 -0700
3
- MIME-Version: 1.0 (Ruby MIME v0.1)
2
+ Message-ID: <357114433@1021851988>
3
+ MIME-Version: 1.0 (Ruby MIME v0.1.0)
4
4
  Content-ID: <10218519780.0838656876757202>
5
5
  Content-Type: text/plain; charset=us-ascii
6
6
 
@@ -1,8 +1,8 @@
1
- Message-ID: <740518531@1061166128>
2
1
  Date: Wed, 29 Oct 2008 21:56:48 -0700
3
- MIME-Version: 1.0 (Ruby MIME v0.1)
2
+ Message-ID: <740518531@1061166128>
3
+ MIME-Version: 1.0 (Ruby MIME v0.1.0)
4
4
  Content-ID: <10611659780.38729886896997>
5
- Content-Transfer-Encoding: binary
6
5
  Content-Type: video/mpeg
6
+ Content-Transfer-Encoding: binary
7
7
 
8
- 0111011001101001011001000110010101101111
8
+ 0110000101110101011001000110100101101111
@@ -0,0 +1,417 @@
1
+ gem 'minitest' # minitest in 1.9 stdlib is crufty
2
+ require 'minitest/autorun'
3
+ require 'mime'
4
+
5
+ Encoding.default_external = 'ASCII-8BIT' # may be able to remove in 2.0
6
+
7
+
8
+ class MIMETest < Minitest::Test
9
+
10
+ CRLF = "\r\n"
11
+ BINARY_DATA = '0110000101110101011001000110100101101111'
12
+
13
+
14
+ ### DISCRETE MESSAGE CONSTRUCTION (SINGLE ENTITY) ###
15
+
16
+ def test_make_top_level_rfc2822_message
17
+ msg = MIME::Message.new
18
+ msg.body = "\r\nmessage body"
19
+ headers, body = msg.to_s.split(CRLF*2)
20
+
21
+ assert_match(/^Message-ID: <\d+@\d+>/, headers)
22
+ assert_match(/^Date: ..., \d{1,2} ... \d{4} \d\d:\d\d:\d\d -\d{4}/, headers)
23
+ assert_match(/^MIME-Version: 1.0 \(Ruby MIME v\d\.\d\.\d\)/, headers)
24
+ assert_equal 3, headers.split(CRLF).count
25
+ assert_equal "message body", body.chomp
26
+ end
27
+
28
+ def test_make_audio_message
29
+ audio_media = MIME::AudioMedia.new(BINARY_DATA, 'audio/midi')
30
+ audio_media.content_transfer_encoding = 'binary'
31
+ assert_equal_mime_msg 'audio.msg', MIME::Message.new(audio_media)
32
+ end
33
+
34
+ def test_make_application_message
35
+ app_media = MIME::ApplicationMedia.new(BINARY_DATA)
36
+ app_media.content_transfer_encoding = 'binary'
37
+ assert_equal_mime_msg 'application.msg', MIME::Message.new(app_media)
38
+ end
39
+
40
+ def test_make_image_message
41
+ image = IO.read(sd('image.jpg'))
42
+ image_media = MIME::ImageMedia.new(image)
43
+ image_media.content_type = 'image/jpeg'
44
+ image_media.content_transfer_encoding = 'binary'
45
+ assert_equal_mime_msg 'image.msg', MIME::Message.new(image_media)
46
+ end
47
+
48
+ def test_make_text_message
49
+ body = MIME::TextMedia.new('a plain text message')
50
+ assert_equal_mime_msg 'text.msg', MIME::Message.new(body)
51
+ end
52
+
53
+ def test_make_video_message
54
+ video_media = MIME::VideoMedia.new(BINARY_DATA)
55
+ video_media.content_type = 'video/mpeg'
56
+ video_media.content_transfer_encoding = 'binary'
57
+ assert_equal_mime_msg 'video.msg', MIME::Message.new(video_media)
58
+ end
59
+
60
+ def test_construction_of_plain_text_email_message
61
+ email = MIME::Message.new
62
+ email.to = {
63
+ 'john@example.com' => 'John',
64
+ 'paul@example.com' => nil,
65
+ 'mary@example.com' => 'Mary'
66
+ }
67
+ email.cc = {'Head Honcho' => 'boss@example.com'}
68
+ email.from = {'jane@example.com' => nil}
69
+ email.subject = 'This is an important email'
70
+ email.body = MIME::TextMedia.new('Hello, world!')
71
+ assert_equal_mime_msg 'plain_text_email.msg', email
72
+ end
73
+
74
+
75
+ ### COMPOSITE MESSAGE CONSTRUCTION (MULTIPLE ENTITIES) ###
76
+
77
+ def test_multipart_form_data_with_text_entities
78
+ txt_data = 'text body'
79
+ htm_data = IO.read(sd('data.htm'))
80
+ xml_data = IO.read(sd('data.xml'))
81
+
82
+ txt = MIME::TextMedia.new(txt_data)
83
+ htm = MIME::TextMedia.new(htm_data, 'text/html')
84
+ xml = MIME::TextMedia.new(xml_data, 'text/xml')
85
+
86
+ form = MIME::MultipartMedia::FormData.new
87
+ form.add_entity txt, 'txt'
88
+ form.add_entity htm, 'htm'
89
+ form.add_entity xml, 'xml'
90
+ assert_equal_mime_msg 'multipart_form_data_text.msg', form
91
+ end
92
+
93
+ def test_multipart_form_data_with_text_and_file_entities
94
+ img1_filename = 'image.jpg'
95
+ img2_filename = 'ruby.png'
96
+ img1_data = IO.read(sd(img1_filename))
97
+ img2_data = IO.read(sd(img2_filename))
98
+ img1 = MIME::ImageMedia.new(img1_data, 'image/jpeg')
99
+ img2 = MIME::ImageMedia.new(img2_data, 'image/png')
100
+ img1.content_transfer_encoding = '8bit'
101
+ img2.content_transfer_encoding = '8bit'
102
+
103
+ desc_data = 'This is plain text description of images.'
104
+ desc = MIME::TextMedia.new(desc_data)
105
+
106
+ form = MIME::MultipartMedia::FormData.new
107
+ form.add_entity desc, 'description'
108
+ form.add_entity img2, 'image_2', img2_filename
109
+ form.add_entity img1, 'image_1', img1_filename
110
+ assert_equal_mime_msg 'multipart_form_data_file_and_text.msg', form
111
+ end
112
+
113
+ # Similar to example 6 in RFC1867.
114
+ def test_multipart_form_data_with_mixed_entity
115
+ txt = MIME::TextMedia.new('Joe Blow')
116
+ img1 = MIME::DiscreteMediaFactory.create(sd('image.jpg'))
117
+ img2 = MIME::DiscreteMediaFactory.create(sd('ruby.png'))
118
+
119
+ mixed_msg = MIME::MultipartMedia::Mixed.new
120
+ mixed_msg.attach_entity(img2)
121
+ mixed_msg.attach_entity(img1)
122
+
123
+ form = MIME::MultipartMedia::FormData.new
124
+ form.add_entity(mixed_msg, 'pics')
125
+ form.add_entity(txt, 'field1')
126
+
127
+ assert_equal_mime_msg 'multipart_form_data_mixed.msg', form
128
+ end
129
+
130
+ def test_multipart_alternative_message
131
+ txt_data = "*Header*\nmessage"
132
+ htm_data = "<html><body><h1>Header</h1><p>message</p></body></html>"
133
+ txt_msg = MIME::TextMedia.new(txt_data)
134
+ htm_msg = MIME::TextMedia.new(htm_data)
135
+
136
+ txt_msg.content_type = ('text/enhanced; charset=us-ascii')
137
+ htm_msg.content_type = ('text/html; charset=iso-8859-1')
138
+
139
+ msg = MIME::MultipartMedia::Alternative.new
140
+ msg.add_entity htm_msg
141
+ msg.add_entity txt_msg
142
+ assert_equal_mime_msg 'multipart_alternative.msg', msg
143
+ end
144
+
145
+ def test_multipart_alternative_with_related_html_entity
146
+ img = MIME::DiscreteMediaFactory.create(sd('ruby.png'))
147
+ img.content_transfer_encoding = 'binary'
148
+
149
+ html_msg = MIME::TextMedia.new(<<EOF, 'text/html; charset=iso-8859-1')
150
+ <html>
151
+ <body>
152
+ <h1>HTML multipart/alternative message</h1>
153
+ <p>txt before pix</p>
154
+ <img alt="cool ruby" src="cid:#{img.content_id}"/>
155
+ <p>txt after pix</p>
156
+ </body>
157
+ </html>
158
+ EOF
159
+ html_msg.content_transfer_encoding = '7bit'
160
+
161
+ text_msg = MIME::TextMedia.new(<<EOF)
162
+ *HTML multipart/alternative message*
163
+ txt before pix
164
+ <cool ruby image>
165
+ txt after pix
166
+ EOF
167
+ text_msg.content_transfer_encoding = '7bit'
168
+
169
+ related_msg = MIME::MultipartMedia::Related.new
170
+ related_msg.inline_entity(img)
171
+ related_msg.add_entity(html_msg)
172
+
173
+ msg = MIME::MultipartMedia::Alternative.new
174
+ msg.add_entity(related_msg)
175
+ msg.add_entity(text_msg)
176
+ assert_equal_mime_msg 'multipart_alternative_related.msg', msg
177
+ end
178
+
179
+ def test_multipart_mixed_with_inline_and_attachment
180
+ msg = MIME::MultipartMedia::Mixed.new
181
+
182
+ open(sd('image.jpg')) do |img_file|
183
+ img_data = img_file.read
184
+ img_msg = MIME::ImageMedia.new(img_data, 'image/jpeg')
185
+ msg.attach_entity(img_msg, 'filename' => img_file.path)
186
+ end
187
+
188
+ msg.inline_entity(MIME::TextMedia.new('Plain Text'))
189
+ assert_equal_mime_msg 'multipart_mixed_inline_and_attachment.msg', msg
190
+ end
191
+
192
+ def test_multipart_mixed_message_using_media_factory
193
+ bot_img = MIME::DiscreteMediaFactory.create(sd('image.jpg'))
194
+ top_img = MIME::DiscreteMediaFactory.create(sd('ruby.png'))
195
+ top_txt = MIME::DiscreteMediaFactory.create(sd('data.htm'))
196
+
197
+ msg = MIME::MultipartMedia::Mixed.new
198
+ msg.attach_entity(bot_img)
199
+ msg.attach_entity(top_img)
200
+ msg.inline_entity(top_txt)
201
+ assert_equal_mime_msg 'multipart_mixed_inline_and_attachment2.msg', msg
202
+ end
203
+
204
+ def test_multipart_related_html_message_with_embedded_image
205
+ img = MIME::DiscreteMediaFactory.create(sd('/ruby.png'))
206
+ img.content_transfer_encoding = 'binary'
207
+
208
+ html_msg = MIME::TextMedia.new(<<EOF, 'text/html; charset=iso-8859-1')
209
+ <html>
210
+ <body>
211
+ <h1>HTML multipart/related message</h1>
212
+ <p>
213
+ txt before pix
214
+ <img alt="cool ruby" src="cid:#{img.content_id}">
215
+ </p>
216
+ <p>txt after pix</p>
217
+ </body>
218
+ </html>
219
+ EOF
220
+ html_msg.content_transfer_encoding = '7bit'
221
+
222
+ msg = MIME::MultipartMedia::Related.new
223
+ msg.inline_entity(img)
224
+ msg.add_entity(html_msg)
225
+ assert_equal_mime_msg 'multipart_related.msg', msg
226
+ end
227
+
228
+
229
+ ### GENERAL RFC ADHERENCE ###
230
+
231
+ def test_boundary_format
232
+ form = MIME::MultipartMedia::FormData.new
233
+ %w(one two three four).each do |ent|
234
+ form.add_entity(MIME::TextMedia.new(ent), ent)
235
+ end
236
+
237
+ boundary = form.to_s.scan(/--Boundary_.*\r\n/).each
238
+ first_boundary = boundary.next
239
+ assert_equal first_boundary, boundary.next
240
+ assert_equal first_boundary, boundary.next
241
+ assert_equal first_boundary, boundary.next
242
+ refute_equal first_boundary, (last_boundary = boundary.next)
243
+ assert_match(/^--Boundary_\d+\.\d+\r\n/, first_boundary)
244
+ assert_match(/^--Boundary_\d+\.\d+--\r\n/, last_boundary)
245
+ end
246
+
247
+ def test_unique_content_ids_in_multipart_message
248
+ form = MIME::MultipartMedia::FormData.new
249
+ %w(one two three four).each do |ent|
250
+ form.add_entity(MIME::TextMedia.new(ent), ent)
251
+ end
252
+
253
+ # 5 IDs: main header ID + 4 entity IDs
254
+ content_ids = form.to_s.scan(/^Content-ID: <(\d+.\d+)>/)
255
+ assert_equal 5, content_ids.flatten.uniq.count # IDs must be unique
256
+ end
257
+
258
+ def test_content_disposition_filenames
259
+ filename1 = 'book.pdf'
260
+ filename2 = 'mini.mov'
261
+ filename3 = 'song.mp3'
262
+ filename4 = 'none.txt'
263
+ filename5 = 'none.htm'
264
+ file1 = MIME::DiscreteMediaFactory.create(sd filename1)
265
+ file2 = MIME::DiscreteMediaFactory.create(sd filename2)
266
+ file3 = MIME::DiscreteMediaFactory.create(sd filename3)
267
+ file4 = MIME::TextMedia.new('txt')
268
+ file5 = MIME::TextMedia.new('htm')
269
+ file6 = MIME::TextMedia.new('xml')
270
+
271
+ form = MIME::MultipartMedia::FormData.new
272
+ # file backed objects
273
+ form.add_entity file1, 'file_1' # none
274
+ form.add_entity file2, 'file_2', filename2 # relative
275
+ form.add_entity file3, 'file_3', "/tmp/#{filename3}" # absolute
276
+ # non-file backed objects
277
+ form.add_entity file4, 'file_4', "/tmp/#{filename4}" # absolute
278
+ form.add_entity file5, 'file_5', filename5 # relative
279
+ form.add_entity file6, 'file_6' # none
280
+ msg = form.to_s
281
+ hdr = 'Content-Disposition: form-data;'
282
+
283
+ # only the file basename should be assigned to filename, never a path
284
+ assert_match(/^#{hdr} name="file_1"; filename="#{filename1}"\r\n/, msg)
285
+ assert_match(/^#{hdr} name="file_2"; filename="#{filename2}"\r\n/, msg)
286
+ assert_match(/^#{hdr} name="file_3"; filename="#{filename3}"\r\n/, msg)
287
+ assert_match(/^#{hdr} name="file_4"; filename="#{filename4}"\r\n/, msg)
288
+ assert_match(/^#{hdr} name="file_5"; filename="#{filename5}"\r\n/, msg)
289
+ assert_match(/^#{hdr} name="file_6"\r\n/, msg)
290
+ end
291
+
292
+
293
+ ### LIBRARY OPERATION ###
294
+
295
+ def test_no_instantiation_of_abstract_classes
296
+ e = MIME::AbstractClassError
297
+ assert_raises(e) {MIME::MediaType.new(nil, nil)}
298
+ assert_raises(e) {MIME::DiscreteMediaType.new(nil)}
299
+ assert_raises(e) {MIME::CompositeMediaType.new(nil)}
300
+ assert_raises(e) {MIME::MultipartMedia.new(nil)}
301
+ end
302
+
303
+ def test_content_type_detection
304
+ (o = Object.new).extend(MIME::ContentTypes)
305
+
306
+ # test file extension; file path is irrelevant here
307
+ assert_equal 'application/pdf', o.file_type('a.pdf')
308
+ assert_equal 'video/quicktime', o.file_type('b.mov')
309
+ assert_equal 'application/octet-stream', o.file_type('c.iso')
310
+ assert_equal 'audio/mpeg', o.file_type('/d/e.mp3')
311
+ assert_equal 'text/css', o.file_type('/f/g/h.css')
312
+ assert_equal nil, o.file_type('i.nil')
313
+
314
+ # test using file object
315
+ img_type = open(sd('ruby.png')) {|f| o.file_type(f)}
316
+ assert_equal 'image/png', img_type
317
+ refute_equal 'image/jpeg', img_type
318
+ end
319
+
320
+ def test_object_instantiation_using_discrete_media_factory
321
+ app_file = sd('book.pdf')
322
+ audio_file = sd('song.mp3')
323
+ text_file = sd('data.xml')
324
+ video_file = sd('mini.mov')
325
+ image_file = sd('image.jpg')
326
+ unknown_file = sd('unknown.yyy')
327
+
328
+ dmf = MIME::DiscreteMediaFactory
329
+
330
+ # test using file path
331
+ assert_kind_of MIME::ApplicationMedia, dmf.create(app_file)
332
+ assert_kind_of MIME::AudioMedia, dmf.create(audio_file)
333
+ assert_kind_of MIME::TextMedia, dmf.create(text_file)
334
+ assert_kind_of MIME::VideoMedia, dmf.create(video_file)
335
+ assert_kind_of MIME::ImageMedia, dmf.create(image_file)
336
+
337
+ # test using file object
338
+ open(image_file) do |image_file_obj|
339
+ assert_kind_of MIME::ImageMedia, dmf.create(image_file_obj)
340
+ end
341
+ open(text_file) do |text_file_obj|
342
+ assert_kind_of MIME::TextMedia, dmf.create(text_file_obj)
343
+ end
344
+
345
+ # raise for unknown file path and File object
346
+ assert_raises(MIME::UnknownContentError) {dmf.create(unknown_file)}
347
+ open(unknown_file) do |unknown_file_obj|
348
+ assert_raises(MIME::UnknownContentError) {dmf.create(unknown_file_obj)}
349
+ end
350
+ end
351
+
352
+ def test_discrete_media_factory_with_specified_invalid_conent_type
353
+ invalid_ctype1 = 'application-x/pdf'
354
+ invalid_ctype2 = 'application'
355
+ valid_ctype = 'application/pdf'
356
+ pdf = sd('book.pdf')
357
+
358
+ assert_raises(MIME::UnknownContentError) {
359
+ MIME::DiscreteMediaFactory.create(pdf, invalid_ctype1)
360
+ }
361
+ assert_raises(MIME::UnknownContentError) {
362
+ MIME::DiscreteMediaFactory.create(pdf, invalid_ctype2)
363
+ }
364
+ assert MIME::DiscreteMediaFactory.create(pdf, valid_ctype)
365
+ end
366
+
367
+ def test_discrete_media_factory_creates_path_singleton_method
368
+ pdf_file_path = sd('book.pdf')
369
+
370
+ media_obj = MIME::DiscreteMediaFactory.create(pdf_file_path)
371
+ assert_equal pdf_file_path, media_obj.path
372
+
373
+ open(pdf_file_path) do |pdf_file_obj|
374
+ media_obj = MIME::DiscreteMediaFactory.create(pdf_file_obj)
375
+ assert_equal pdf_file_path, media_obj.path
376
+ end
377
+ end
378
+
379
+
380
+ private
381
+
382
+ #
383
+ # Test equality of the +expected+ and +actual+ MIME messages.
384
+ #
385
+ def assert_equal_mime_msg expected, actual
386
+ m1 = generalize_msg(IO.read(sd(expected)))
387
+ m2 = generalize_msg(actual.to_s)
388
+ assert_equal m1, m2
389
+ end
390
+
391
+ #
392
+ # Remove unique identifiers to make +message+ structurally comparable.
393
+ #
394
+ def generalize_msg message
395
+ # Very delicate REs that are inter-dependent, be careful!
396
+ cid = /cid:\d+\.\d+/
397
+ id = /-ID: <\d+[@.]\d+>\r\n/
398
+ boundary = /Boundary_\d+\.\d+/
399
+ date = /^Date: .* -\d{4}\r\n/
400
+ version = /Ruby MIME v\d\.\d\.\d/
401
+
402
+ message.
403
+ gsub(cid, "cid").
404
+ gsub(id, "-ID:\r\n").
405
+ gsub(boundary, "Boundary_").
406
+ sub(date, "Date:\r\n").
407
+ sub(version, "Ruby MIME")
408
+ end
409
+
410
+ #
411
+ # Return the path of the scaffold +file+.
412
+ #
413
+ def sd file
414
+ File.join(File.dirname(__FILE__), 'scaffold', file)
415
+ end
416
+
417
+ end