mime 0.1 → 0.2.0

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.
@@ -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