mbailey-paperclip 2.3.2

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.
Files changed (56) hide show
  1. data/LICENSE +26 -0
  2. data/README.rdoc +179 -0
  3. data/Rakefile +76 -0
  4. data/generators/paperclip/USAGE +5 -0
  5. data/generators/paperclip/paperclip_generator.rb +27 -0
  6. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  7. data/init.rb +1 -0
  8. data/lib/generators/paperclip/USAGE +8 -0
  9. data/lib/generators/paperclip/paperclip_generator.rb +31 -0
  10. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  11. data/lib/paperclip/attachment.rb +326 -0
  12. data/lib/paperclip/callback_compatability.rb +61 -0
  13. data/lib/paperclip/geometry.rb +115 -0
  14. data/lib/paperclip/interpolations.rb +108 -0
  15. data/lib/paperclip/iostream.rb +59 -0
  16. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  17. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +74 -0
  18. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  19. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  20. data/lib/paperclip/matchers.rb +33 -0
  21. data/lib/paperclip/processor.rb +49 -0
  22. data/lib/paperclip/railtie.rb +24 -0
  23. data/lib/paperclip/storage.rb +247 -0
  24. data/lib/paperclip/style.rb +90 -0
  25. data/lib/paperclip/thumbnail.rb +78 -0
  26. data/lib/paperclip/upfile.rb +52 -0
  27. data/lib/paperclip/version.rb +3 -0
  28. data/lib/paperclip.rb +397 -0
  29. data/lib/tasks/paperclip.rake +79 -0
  30. data/rails/init.rb +2 -0
  31. data/shoulda_macros/paperclip.rb +119 -0
  32. data/test/attachment_test.rb +758 -0
  33. data/test/database.yml +4 -0
  34. data/test/fixtures/12k.png +0 -0
  35. data/test/fixtures/50x50.png +0 -0
  36. data/test/fixtures/5k.png +0 -0
  37. data/test/fixtures/bad.png +1 -0
  38. data/test/fixtures/s3.yml +8 -0
  39. data/test/fixtures/text.txt +0 -0
  40. data/test/fixtures/twopage.pdf +0 -0
  41. data/test/geometry_test.rb +177 -0
  42. data/test/helper.rb +148 -0
  43. data/test/integration_test.rb +483 -0
  44. data/test/interpolations_test.rb +124 -0
  45. data/test/iostream_test.rb +78 -0
  46. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  47. data/test/matchers/validate_attachment_content_type_matcher_test.rb +37 -0
  48. data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
  49. data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
  50. data/test/paperclip_test.rb +317 -0
  51. data/test/processor_test.rb +10 -0
  52. data/test/storage_test.rb +343 -0
  53. data/test/style_test.rb +141 -0
  54. data/test/thumbnail_test.rb +227 -0
  55. data/test/upfile_test.rb +36 -0
  56. metadata +205 -0
@@ -0,0 +1,483 @@
1
+ require 'test/helper'
2
+
3
+ class IntegrationTest < Test::Unit::TestCase
4
+ context "Many models at once" do
5
+ setup do
6
+ rebuild_model
7
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
8
+ 300.times do |i|
9
+ Dummy.create! :avatar => @file
10
+ end
11
+ end
12
+
13
+ should "not exceed the open file limit" do
14
+ assert_nothing_raised do
15
+ dummies = Dummy.find(:all)
16
+ dummies.each { |dummy| dummy.avatar }
17
+ end
18
+ end
19
+ end
20
+
21
+ context "An attachment" do
22
+ setup do
23
+ rebuild_model :styles => { :thumb => "50x50#" }
24
+ @dummy = Dummy.new
25
+ @file = File.new(File.join(File.dirname(__FILE__),
26
+ "fixtures",
27
+ "5k.png"), 'rb')
28
+ @dummy.avatar = @file
29
+ assert @dummy.save
30
+ end
31
+
32
+ teardown { @file.close }
33
+
34
+ should "create its thumbnails properly" do
35
+ assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
36
+ end
37
+
38
+ context "redefining its attachment styles" do
39
+ setup do
40
+ Dummy.class_eval do
41
+ has_attached_file :avatar, :styles => { :thumb => "150x25#" }
42
+ has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } }
43
+ end
44
+ @d2 = Dummy.find(@dummy.id)
45
+ @d2.avatar.reprocess!
46
+ @d2.save
47
+ end
48
+
49
+ should "create its thumbnails properly" do
50
+ assert_match /\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
51
+ assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"`
52
+ end
53
+ end
54
+ end
55
+
56
+ context "A model that modifies its original" do
57
+ setup do
58
+ rebuild_model :styles => { :original => "2x2#" }
59
+ @dummy = Dummy.new
60
+ @file = File.new(File.join(File.dirname(__FILE__),
61
+ "fixtures",
62
+ "5k.png"), 'rb')
63
+ @dummy.avatar = @file
64
+ end
65
+
66
+ should "report the file size of the processed file and not the original" do
67
+ assert_not_equal @file.size, @dummy.avatar.size
68
+ end
69
+
70
+ teardown { @file.close }
71
+ end
72
+
73
+ context "A model with attachments scoped under an id" do
74
+ setup do
75
+ rebuild_model :styles => { :large => "100x100",
76
+ :medium => "50x50" },
77
+ :path => ":rails_root/tmp/:id/:attachments/:style.:extension"
78
+ @dummy = Dummy.new
79
+ @file = File.new(File.join(File.dirname(__FILE__),
80
+ "fixtures",
81
+ "5k.png"), 'rb')
82
+ @dummy.avatar = @file
83
+ end
84
+
85
+ teardown { @file.close }
86
+
87
+ context "when saved" do
88
+ setup do
89
+ @dummy.save
90
+ @saved_path = @dummy.avatar.path(:large)
91
+ end
92
+
93
+ should "have a large file in the right place" do
94
+ assert File.exists?(@dummy.avatar.path(:large))
95
+ end
96
+
97
+ context "and deleted" do
98
+ setup do
99
+ @dummy.avatar.clear
100
+ @dummy.save
101
+ end
102
+
103
+ should "not have a large file in the right place anymore" do
104
+ assert ! File.exists?(@saved_path)
105
+ end
106
+
107
+ should "not have its next two parent directories" do
108
+ assert ! File.exists?(File.dirname(@saved_path))
109
+ assert ! File.exists?(File.dirname(File.dirname(@saved_path)))
110
+ end
111
+
112
+ before_should "not die if an unexpected SystemCallError happens" do
113
+ FileUtils.stubs(:rmdir).raises(Errno::EPIPE)
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ context "A model with no attachment validation" do
120
+ setup do
121
+ rebuild_model :styles => { :large => "300x300>",
122
+ :medium => "100x100",
123
+ :thumb => ["32x32#", :gif] },
124
+ :default_style => :medium,
125
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
126
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
127
+ @dummy = Dummy.new
128
+ end
129
+
130
+ should "have its definition return false when asked about whiny_thumbnails" do
131
+ assert ! Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
132
+ end
133
+
134
+ context "when validates_attachment_thumbnails is called" do
135
+ setup do
136
+ Dummy.validates_attachment_thumbnails :avatar
137
+ end
138
+
139
+ should "have its definition return true when asked about whiny_thumbnails" do
140
+ assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
141
+ end
142
+ end
143
+
144
+ context "redefined to have attachment validations" do
145
+ setup do
146
+ rebuild_model :styles => { :large => "300x300>",
147
+ :medium => "100x100",
148
+ :thumb => ["32x32#", :gif] },
149
+ :whiny_thumbnails => true,
150
+ :default_style => :medium,
151
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
152
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
153
+ end
154
+
155
+ should "have its definition return true when asked about whiny_thumbnails" do
156
+ assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
157
+ end
158
+ end
159
+ end
160
+
161
+ context "A model with no convert_options setting" do
162
+ setup do
163
+ rebuild_model :styles => { :large => "300x300>",
164
+ :medium => "100x100",
165
+ :thumb => ["32x32#", :gif] },
166
+ :default_style => :medium,
167
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
168
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
169
+ @dummy = Dummy.new
170
+ end
171
+
172
+ should "have its definition return nil when asked about convert_options" do
173
+ assert ! Dummy.attachment_definitions[:avatar][:convert_options]
174
+ end
175
+
176
+ context "redefined to have convert_options setting" do
177
+ setup do
178
+ rebuild_model :styles => { :large => "300x300>",
179
+ :medium => "100x100",
180
+ :thumb => ["32x32#", :gif] },
181
+ :convert_options => "-strip -depth 8",
182
+ :default_style => :medium,
183
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
184
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
185
+ end
186
+
187
+ should "have its definition return convert_options value when asked about convert_options" do
188
+ assert_equal "-strip -depth 8", Dummy.attachment_definitions[:avatar][:convert_options]
189
+ end
190
+ end
191
+ end
192
+
193
+ context "A model with a filesystem attachment" do
194
+ setup do
195
+ rebuild_model :styles => { :large => "300x300>",
196
+ :medium => "100x100",
197
+ :thumb => ["32x32#", :gif] },
198
+ :whiny_thumbnails => true,
199
+ :default_style => :medium,
200
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
201
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
202
+ @dummy = Dummy.new
203
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
204
+ @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb')
205
+
206
+ assert @dummy.avatar = @file
207
+ assert @dummy.valid?
208
+ assert @dummy.save
209
+ end
210
+
211
+ should "write and delete its files" do
212
+ [["434x66", :original],
213
+ ["300x46", :large],
214
+ ["100x15", :medium],
215
+ ["32x32", :thumb]].each do |geo, style|
216
+ cmd = %Q[identify -format "%wx%h" "#{@dummy.avatar.path(style)}"]
217
+ assert_equal geo, `#{cmd}`.chomp, cmd
218
+ end
219
+
220
+ saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) }
221
+
222
+ @d2 = Dummy.find(@dummy.id)
223
+ assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path}"`.chomp
224
+ assert_equal "434x66", `identify -format "%wx%h" "#{@d2.avatar.path(:original)}"`.chomp
225
+ assert_equal "300x46", `identify -format "%wx%h" "#{@d2.avatar.path(:large)}"`.chomp
226
+ assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp
227
+ assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp
228
+
229
+ @dummy.avatar = "not a valid file but not nil"
230
+ assert_equal File.basename(@file.path), @dummy.avatar_file_name
231
+ assert @dummy.valid?
232
+ assert @dummy.save
233
+
234
+ saved_paths.each do |p|
235
+ assert File.exists?(p)
236
+ end
237
+
238
+ @dummy.avatar.clear
239
+ assert_nil @dummy.avatar_file_name
240
+ assert @dummy.valid?
241
+ assert @dummy.save
242
+
243
+ saved_paths.each do |p|
244
+ assert ! File.exists?(p)
245
+ end
246
+
247
+ @d2 = Dummy.find(@dummy.id)
248
+ assert_nil @d2.avatar_file_name
249
+ end
250
+
251
+ should "work exactly the same when new as when reloaded" do
252
+ @d2 = Dummy.find(@dummy.id)
253
+
254
+ assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
255
+ [:thumb, :medium, :large, :original].each do |style|
256
+ assert_equal @dummy.avatar.path(style), @d2.avatar.path(style)
257
+ end
258
+
259
+ saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) }
260
+
261
+ @d2.avatar.clear
262
+ assert @d2.save
263
+
264
+ saved_paths.each do |p|
265
+ assert ! File.exists?(p)
266
+ end
267
+ end
268
+
269
+ should "know the difference between good files, bad files, and not files" do
270
+ expected = @dummy.avatar.to_file
271
+ @dummy.avatar = "not a file"
272
+ assert @dummy.valid?
273
+ assert_equal expected.path, @dummy.avatar.path
274
+ expected.close
275
+
276
+ @dummy.avatar = @bad_file
277
+ assert ! @dummy.valid?
278
+ end
279
+
280
+ should "know the difference between good files, bad files, and not files when validating" do
281
+ Dummy.validates_attachment_presence :avatar
282
+ @d2 = Dummy.find(@dummy.id)
283
+ @d2.avatar = @file
284
+ assert @d2.valid?, @d2.errors.full_messages.inspect
285
+ @d2.avatar = @bad_file
286
+ assert ! @d2.valid?
287
+ end
288
+
289
+ should "be able to reload without saving and not have the file disappear" do
290
+ @dummy.avatar = @file
291
+ assert @dummy.save
292
+ @dummy.avatar.clear
293
+ assert_nil @dummy.avatar_file_name
294
+ @dummy.reload
295
+ assert_equal "5k.png", @dummy.avatar_file_name
296
+ end
297
+
298
+ context "that is assigned its file from another Paperclip attachment" do
299
+ setup do
300
+ @dummy2 = Dummy.new
301
+ @file2 = File.new(File.join(FIXTURES_DIR, "12k.png"), 'rb')
302
+ assert @dummy2.avatar = @file2
303
+ @dummy2.save
304
+ end
305
+
306
+ should "work when assigned a file" do
307
+ assert_not_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
308
+ `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
309
+
310
+ assert @dummy.avatar = @dummy2.avatar
311
+ @dummy.save
312
+ assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
313
+ `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
314
+ end
315
+ end
316
+
317
+ end
318
+
319
+ context "A model with an attachments association and a Paperclip attachment" do
320
+ setup do
321
+ Dummy.class_eval do
322
+ has_many :attachments, :class_name => 'Dummy'
323
+ end
324
+
325
+ @dummy = Dummy.new
326
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__),
327
+ "fixtures",
328
+ "5k.png"), 'rb')
329
+ end
330
+
331
+ should "should not error when saving" do
332
+ assert_nothing_raised do
333
+ @dummy.save!
334
+ end
335
+ end
336
+ end
337
+
338
+ if ENV['S3_TEST_BUCKET']
339
+ def s3_files_for attachment
340
+ [:thumb, :medium, :large, :original].inject({}) do |files, style|
341
+ data = `curl "#{attachment.url(style)}" 2>/dev/null`.chomp
342
+ t = Tempfile.new("paperclip-test")
343
+ t.binmode
344
+ t.write(data)
345
+ t.rewind
346
+ files[style] = t
347
+ files
348
+ end
349
+ end
350
+
351
+ def s3_headers_for attachment, style
352
+ `curl --head "#{attachment.url(style)}" 2>/dev/null`.split("\n").inject({}) do |h,head|
353
+ split_head = head.chomp.split(/\s*:\s*/, 2)
354
+ h[split_head.first.downcase] = split_head.last unless split_head.empty?
355
+ h
356
+ end
357
+ end
358
+
359
+ context "A model with an S3 attachment" do
360
+ setup do
361
+ rebuild_model :styles => { :large => "300x300>",
362
+ :medium => "100x100",
363
+ :thumb => ["32x32#", :gif] },
364
+ :storage => :s3,
365
+ :whiny_thumbnails => true,
366
+ # :s3_options => {:logger => Logger.new(StringIO.new)},
367
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")),
368
+ :default_style => :medium,
369
+ :bucket => ENV['S3_TEST_BUCKET'],
370
+ :path => ":class/:attachment/:id/:style/:basename.:extension"
371
+ @dummy = Dummy.new
372
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
373
+ @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb')
374
+
375
+ assert @dummy.avatar = @file
376
+ assert @dummy.valid?
377
+ assert @dummy.save
378
+
379
+ @files_on_s3 = s3_files_for @dummy.avatar
380
+ end
381
+
382
+ should "have the same contents as the original" do
383
+ @file.rewind
384
+ assert_equal @file.read, @files_on_s3[:original].read
385
+ end
386
+
387
+ should "write and delete its files" do
388
+ [["434x66", :original],
389
+ ["300x46", :large],
390
+ ["100x15", :medium],
391
+ ["32x32", :thumb]].each do |geo, style|
392
+ cmd = %Q[identify -format "%wx%h" "#{@files_on_s3[style].path}"]
393
+ assert_equal geo, `#{cmd}`.chomp, cmd
394
+ end
395
+
396
+ @d2 = Dummy.find(@dummy.id)
397
+ @d2_files = s3_files_for @d2.avatar
398
+ [["434x66", :original],
399
+ ["300x46", :large],
400
+ ["100x15", :medium],
401
+ ["32x32", :thumb]].each do |geo, style|
402
+ cmd = %Q[identify -format "%wx%h" "#{@d2_files[style].path}"]
403
+ assert_equal geo, `#{cmd}`.chomp, cmd
404
+ end
405
+
406
+ @dummy.avatar = "not a valid file but not nil"
407
+ assert_equal File.basename(@file.path), @dummy.avatar_file_name
408
+ assert @dummy.valid?
409
+ assert @dummy.save
410
+
411
+ [:thumb, :medium, :large, :original].each do |style|
412
+ assert @dummy.avatar.exists?(style)
413
+ end
414
+
415
+ @dummy.avatar.clear
416
+ assert_nil @dummy.avatar_file_name
417
+ assert @dummy.valid?
418
+ assert @dummy.save
419
+
420
+ [:thumb, :medium, :large, :original].each do |style|
421
+ assert ! @dummy.avatar.exists?(style)
422
+ end
423
+
424
+ @d2 = Dummy.find(@dummy.id)
425
+ assert_nil @d2.avatar_file_name
426
+ end
427
+
428
+ should "work exactly the same when new as when reloaded" do
429
+ @d2 = Dummy.find(@dummy.id)
430
+
431
+ assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
432
+ [:thumb, :medium, :large, :original].each do |style|
433
+ assert_equal @dummy.avatar.to_file(style).read, @d2.avatar.to_file(style).read
434
+ end
435
+
436
+ saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) }
437
+
438
+ @d2.avatar.clear
439
+ assert @d2.save
440
+
441
+ [:thumb, :medium, :large, :original].each do |style|
442
+ assert ! @dummy.avatar.exists?(style)
443
+ end
444
+ end
445
+
446
+ should "know the difference between good files, bad files, not files, and nil" do
447
+ expected = @dummy.avatar.to_file
448
+ @dummy.avatar = "not a file"
449
+ assert @dummy.valid?
450
+ assert_equal expected.read, @dummy.avatar.to_file.read
451
+
452
+ @dummy.avatar = @bad_file
453
+ assert ! @dummy.valid?
454
+ @dummy.avatar = nil
455
+ assert @dummy.valid?
456
+
457
+ Dummy.validates_attachment_presence :avatar
458
+ @d2 = Dummy.find(@dummy.id)
459
+ @d2.avatar = @file
460
+ assert @d2.valid?
461
+ @d2.avatar = @bad_file
462
+ assert ! @d2.valid?
463
+ @d2.avatar = nil
464
+ assert ! @d2.valid?
465
+ end
466
+
467
+ should "be able to reload without saving and not have the file disappear" do
468
+ @dummy.avatar = @file
469
+ assert @dummy.save
470
+ @dummy.avatar = nil
471
+ assert_nil @dummy.avatar_file_name
472
+ @dummy.reload
473
+ assert_equal "5k.png", @dummy.avatar_file_name
474
+ end
475
+
476
+ should "have the right content type" do
477
+ headers = s3_headers_for(@dummy.avatar, :original)
478
+ assert_equal 'image/png', headers['content-type']
479
+ end
480
+ end
481
+ end
482
+ end
483
+
@@ -0,0 +1,124 @@
1
+ require 'test/helper'
2
+
3
+ class InterpolationsTest < Test::Unit::TestCase
4
+ should "return all methods but the infrastructure when sent #all" do
5
+ methods = Paperclip::Interpolations.all
6
+ assert ! methods.include?(:[])
7
+ assert ! methods.include?(:[]=)
8
+ assert ! methods.include?(:all)
9
+ methods.each do |m|
10
+ assert Paperclip::Interpolations.respond_to?(m)
11
+ end
12
+ end
13
+
14
+ should "return the Rails.root" do
15
+ assert_equal Rails.root, Paperclip::Interpolations.rails_root(:attachment, :style)
16
+ end
17
+
18
+ should "return the Rails.env" do
19
+ assert_equal Rails.env, Paperclip::Interpolations.rails_env(:attachment, :style)
20
+ end
21
+
22
+ should "return the class of the Interpolations module when called with no params" do
23
+ assert_equal Module, Paperclip::Interpolations.class
24
+ end
25
+
26
+ should "return the class of the instance" do
27
+ attachment = mock
28
+ attachment.expects(:instance).returns(attachment)
29
+ attachment.expects(:class).returns("Thing")
30
+ assert_equal "things", Paperclip::Interpolations.class(attachment, :style)
31
+ end
32
+
33
+ should "return the basename of the file" do
34
+ attachment = mock
35
+ attachment.expects(:original_filename).returns("one.jpg").times(2)
36
+ assert_equal "one", Paperclip::Interpolations.basename(attachment, :style)
37
+ end
38
+
39
+ should "return the extension of the file" do
40
+ attachment = mock
41
+ attachment.expects(:original_filename).returns("one.jpg")
42
+ attachment.expects(:styles).returns({})
43
+ assert_equal "jpg", Paperclip::Interpolations.extension(attachment, :style)
44
+ end
45
+
46
+ should "return the extension of the file as the format if defined in the style" do
47
+ attachment = mock
48
+ attachment.expects(:original_filename).never
49
+ attachment.expects(:styles).returns({:style => {:format => "png"}})
50
+ assert_equal "png", Paperclip::Interpolations.extension(attachment, :style)
51
+ end
52
+
53
+ should "return the id of the attachment" do
54
+ attachment = mock
55
+ attachment.expects(:id).returns(23)
56
+ attachment.expects(:instance).returns(attachment)
57
+ assert_equal 23, Paperclip::Interpolations.id(attachment, :style)
58
+ end
59
+
60
+ should "return the partitioned id of the attachment" do
61
+ attachment = mock
62
+ attachment.expects(:id).returns(23)
63
+ attachment.expects(:instance).returns(attachment)
64
+ assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style)
65
+ end
66
+
67
+ should "return the name of the attachment" do
68
+ attachment = mock
69
+ attachment.expects(:name).returns("file")
70
+ assert_equal "files", Paperclip::Interpolations.attachment(attachment, :style)
71
+ end
72
+
73
+ should "return the style" do
74
+ assert_equal :style, Paperclip::Interpolations.style(:attachment, :style)
75
+ end
76
+
77
+ should "return the default style" do
78
+ attachment = mock
79
+ attachment.expects(:default_style).returns(:default_style)
80
+ assert_equal :default_style, Paperclip::Interpolations.style(attachment, nil)
81
+ end
82
+
83
+ should "reinterpolate :url" do
84
+ attachment = mock
85
+ attachment.expects(:options).returns({:url => ":id"})
86
+ attachment.expects(:url).with(:style, false).returns("1234")
87
+ assert_equal "1234", Paperclip::Interpolations.url(attachment, :style)
88
+ end
89
+
90
+ should "raise if infinite loop detcted reinterpolating :url" do
91
+ attachment = mock
92
+ attachment.expects(:options).returns({:url => ":url"})
93
+ assert_raises(Paperclip::InfiniteInterpolationError){ Paperclip::Interpolations.url(attachment, :style) }
94
+ end
95
+
96
+ should "return the filename as basename.extension" do
97
+ attachment = mock
98
+ attachment.expects(:styles).returns({})
99
+ attachment.expects(:original_filename).returns("one.jpg").times(3)
100
+ assert_equal "one.jpg", Paperclip::Interpolations.filename(attachment, :style)
101
+ end
102
+
103
+ should "return the filename as basename.extension when format supplied" do
104
+ attachment = mock
105
+ attachment.expects(:styles).returns({:style => {:format => :png}})
106
+ attachment.expects(:original_filename).returns("one.jpg").times(2)
107
+ assert_equal "one.png", Paperclip::Interpolations.filename(attachment, :style)
108
+ end
109
+
110
+ should "return the timestamp" do
111
+ now = Time.now
112
+ attachment = mock
113
+ attachment.expects(:instance_read).with(:updated_at).returns(now)
114
+ assert_equal now.to_s, Paperclip::Interpolations.timestamp(attachment, :style)
115
+ end
116
+
117
+ should "call all expected interpolations with the given arguments" do
118
+ Paperclip::Interpolations.expects(:id).with(:attachment, :style).returns(1234)
119
+ Paperclip::Interpolations.expects(:attachment).with(:attachment, :style).returns("attachments")
120
+ Paperclip::Interpolations.expects(:notreal).never
121
+ value = Paperclip::Interpolations.interpolate(":notreal/:id/:attachment", :attachment, :style)
122
+ assert_equal ":notreal/1234/attachments", value
123
+ end
124
+ end
@@ -0,0 +1,78 @@
1
+ require 'test/helper'
2
+
3
+ class IOStreamTest < Test::Unit::TestCase
4
+ context "IOStream" do
5
+ should "be included in IO, File, Tempfile, and StringIO" do
6
+ [IO, File, Tempfile, StringIO].each do |klass|
7
+ assert klass.included_modules.include?(IOStream), "Not in #{klass}"
8
+ end
9
+ end
10
+ end
11
+
12
+ context "A file" do
13
+ setup do
14
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
15
+ end
16
+
17
+ teardown { @file.close }
18
+
19
+ context "that is sent #stream_to" do
20
+
21
+ context "and given a String" do
22
+ setup do
23
+ FileUtils.mkdir_p(File.join(ROOT, 'tmp'))
24
+ assert @result = @file.stream_to(File.join(ROOT, 'tmp', 'iostream.string.test'))
25
+ end
26
+
27
+ should "return a File" do
28
+ assert @result.is_a?(File)
29
+ end
30
+
31
+ should "contain the same data as the original file" do
32
+ @file.rewind; @result.rewind
33
+ assert_equal @file.read, @result.read
34
+ end
35
+ end
36
+
37
+ context "and given a Tempfile" do
38
+ setup do
39
+ tempfile = Tempfile.new('iostream.test')
40
+ tempfile.binmode
41
+ assert @result = @file.stream_to(tempfile)
42
+ end
43
+
44
+ should "return a Tempfile" do
45
+ assert @result.is_a?(Tempfile)
46
+ end
47
+
48
+ should "contain the same data as the original file" do
49
+ @file.rewind; @result.rewind
50
+ assert_equal @file.read, @result.read
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ context "that is sent #to_tempfile" do
57
+ setup do
58
+ assert @tempfile = @file.to_tempfile
59
+ end
60
+
61
+ should "convert it to a Paperclip Tempfile" do
62
+ assert @tempfile.is_a?(Paperclip::Tempfile)
63
+ end
64
+
65
+ should "have the name be based on the original_filename" do
66
+ name = File.basename(@file.path)
67
+ extension = File.extname(name)
68
+ basename = File.basename(name, extension)
69
+ assert_match %r[^stream.*?#{Regexp.quote(extension)}], File.basename(@tempfile.path)
70
+ end
71
+
72
+ should "have the Tempfile contain the same data as the file" do
73
+ @file.rewind; @tempfile.rewind
74
+ assert_equal @file.read, @tempfile.read
75
+ end
76
+ end
77
+ end
78
+ end