rsturim-paperclip 2.2.9.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 (47) hide show
  1. data/LICENSE +26 -0
  2. data/README.rdoc +174 -0
  3. data/Rakefile +99 -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/paperclip.rb +350 -0
  9. data/lib/paperclip/attachment.rb +413 -0
  10. data/lib/paperclip/callback_compatability.rb +33 -0
  11. data/lib/paperclip/geometry.rb +115 -0
  12. data/lib/paperclip/interpolations.rb +105 -0
  13. data/lib/paperclip/iostream.rb +58 -0
  14. data/lib/paperclip/matchers.rb +4 -0
  15. data/lib/paperclip/matchers/have_attached_file_matcher.rb +49 -0
  16. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +66 -0
  17. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +48 -0
  18. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +83 -0
  19. data/lib/paperclip/processor.rb +49 -0
  20. data/lib/paperclip/storage.rb +241 -0
  21. data/lib/paperclip/thumbnail.rb +70 -0
  22. data/lib/paperclip/upfile.rb +48 -0
  23. data/shoulda_macros/paperclip.rb +68 -0
  24. data/tasks/paperclip_tasks.rake +79 -0
  25. data/test/attachment_test.rb +768 -0
  26. data/test/database.yml +4 -0
  27. data/test/fixtures/12k.png +0 -0
  28. data/test/fixtures/50x50.png +0 -0
  29. data/test/fixtures/5k.png +0 -0
  30. data/test/fixtures/bad.png +1 -0
  31. data/test/fixtures/s3.yml +4 -0
  32. data/test/fixtures/text.txt +0 -0
  33. data/test/fixtures/twopage.pdf +0 -0
  34. data/test/geometry_test.rb +177 -0
  35. data/test/helper.rb +100 -0
  36. data/test/integration_test.rb +481 -0
  37. data/test/interpolations_test.rb +120 -0
  38. data/test/iostream_test.rb +71 -0
  39. data/test/matchers/have_attached_file_matcher_test.rb +21 -0
  40. data/test/matchers/validate_attachment_content_type_matcher_test.rb +30 -0
  41. data/test/matchers/validate_attachment_presence_matcher_test.rb +21 -0
  42. data/test/matchers/validate_attachment_size_matcher_test.rb +50 -0
  43. data/test/paperclip_test.rb +291 -0
  44. data/test/processor_test.rb +10 -0
  45. data/test/storage_test.rb +293 -0
  46. data/test/thumbnail_test.rb +177 -0
  47. metadata +124 -0
@@ -0,0 +1,768 @@
1
+ require 'test/helper'
2
+
3
+ class Dummy
4
+ # This is a dummy class
5
+ end
6
+
7
+ class AttachmentTest < Test::Unit::TestCase
8
+ should "return the path based on the url by default" do
9
+ @attachment = attachment :url => "/:class/:id/:basename"
10
+ @model = @attachment.instance
11
+ @model.id = 1234
12
+ @model.avatar_file_name = "fake.jpg"
13
+ assert_equal "#{RAILS_ROOT}/public/fake_models/1234/fake", @attachment.path
14
+ end
15
+
16
+ context "Attachment default_options" do
17
+ setup do
18
+ rebuild_model
19
+ @old_default_options = Paperclip::Attachment.default_options.dup
20
+ @new_default_options = @old_default_options.merge({
21
+ :path => "argle/bargle",
22
+ :url => "fooferon",
23
+ :default_url => "not here.png"
24
+ })
25
+ end
26
+
27
+ teardown do
28
+ Paperclip::Attachment.default_options.merge! @old_default_options
29
+ end
30
+
31
+ should "be overrideable" do
32
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
33
+ @new_default_options.keys.each do |key|
34
+ assert_equal @new_default_options[key],
35
+ Paperclip::Attachment.default_options[key]
36
+ end
37
+ end
38
+
39
+ context "without an Attachment" do
40
+ setup do
41
+ @dummy = Dummy.new
42
+ end
43
+
44
+ should "return false when asked exists?" do
45
+ assert !@dummy.avatar.exists?
46
+ end
47
+ end
48
+
49
+ context "on an Attachment" do
50
+ setup do
51
+ @dummy = Dummy.new
52
+ @attachment = @dummy.avatar
53
+ end
54
+
55
+ Paperclip::Attachment.default_options.keys.each do |key|
56
+ should "be the default_options for #{key}" do
57
+ assert_equal @old_default_options[key],
58
+ @attachment.instance_variable_get("@#{key}"),
59
+ key
60
+ end
61
+ end
62
+
63
+ context "when redefined" do
64
+ setup do
65
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
66
+ @dummy = Dummy.new
67
+ @attachment = @dummy.avatar
68
+ end
69
+
70
+ Paperclip::Attachment.default_options.keys.each do |key|
71
+ should "be the new default_options for #{key}" do
72
+ assert_equal @new_default_options[key],
73
+ @attachment.instance_variable_get("@#{key}"),
74
+ key
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ context "An attachment with similarly named interpolations" do
82
+ setup do
83
+ rebuild_model :path => ":id.omg/:id-bbq/:idwhat/:id_partition.wtf"
84
+ @dummy = Dummy.new
85
+ @dummy.stubs(:id).returns(1024)
86
+ @file = File.new(File.join(File.dirname(__FILE__),
87
+ "fixtures",
88
+ "5k.png"), 'rb')
89
+ @dummy.avatar = @file
90
+ end
91
+
92
+ teardown { @file.close }
93
+
94
+ should "make sure that they are interpolated correctly" do
95
+ assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path
96
+ end
97
+ end
98
+
99
+ context "An attachment with a :rails_env interpolation" do
100
+ setup do
101
+ @rails_env = "blah"
102
+ @id = 1024
103
+ rebuild_model :path => ":rails_env/:id.png"
104
+ @dummy = Dummy.new
105
+ @dummy.stubs(:id).returns(@id)
106
+ @file = StringIO.new(".")
107
+ @dummy.avatar = @file
108
+ end
109
+
110
+ should "return the proper path" do
111
+ temporary_rails_env(@rails_env) {
112
+ assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path
113
+ }
114
+ end
115
+ end
116
+
117
+ context "An attachment with a default style and an extension interpolation" do
118
+ setup do
119
+ @attachment = attachment :path => ":basename.:extension",
120
+ :styles => { :default => ["100x100", :png] },
121
+ :default_style => :default
122
+ @file = StringIO.new("...")
123
+ @file.expects(:original_filename).returns("file.jpg")
124
+ end
125
+ should "return the right extension for the path" do
126
+ @attachment.assign(@file)
127
+ assert_equal "file.png", @attachment.path
128
+ end
129
+ end
130
+
131
+ context "An attachment with :convert_options" do
132
+ setup do
133
+ rebuild_model :styles => {
134
+ :thumb => "100x100",
135
+ :large => "400x400"
136
+ },
137
+ :convert_options => {
138
+ :all => "-do_stuff",
139
+ :thumb => "-thumbnailize"
140
+ }
141
+ @dummy = Dummy.new
142
+ @dummy.avatar
143
+ end
144
+
145
+ should "report the correct options when sent #extra_options_for(:thumb)" do
146
+ assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
147
+ end
148
+
149
+ should "report the correct options when sent #extra_options_for(:large)" do
150
+ assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
151
+ end
152
+
153
+ before_should "call extra_options_for(:thumb/:large)" do
154
+ Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb)
155
+ Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large)
156
+ end
157
+ end
158
+
159
+ context "An attachment with :convert_options that is a proc" do
160
+ setup do
161
+ rebuild_model :styles => {
162
+ :thumb => "100x100",
163
+ :large => "400x400"
164
+ },
165
+ :convert_options => {
166
+ :all => lambda{|i| i.all },
167
+ :thumb => lambda{|i| i.thumb }
168
+ }
169
+ Dummy.class_eval do
170
+ def all; "-all"; end
171
+ def thumb; "-thumb"; end
172
+ end
173
+ @dummy = Dummy.new
174
+ @dummy.avatar
175
+ end
176
+
177
+ should "report the correct options when sent #extra_options_for(:thumb)" do
178
+ assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
179
+ end
180
+
181
+ should "report the correct options when sent #extra_options_for(:large)" do
182
+ assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
183
+ end
184
+
185
+ before_should "call extra_options_for(:thumb/:large)" do
186
+ Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb)
187
+ Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large)
188
+ end
189
+ end
190
+
191
+ context "An attachment with :path that is a proc" do
192
+ setup do
193
+ rebuild_model :path => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
194
+
195
+ @file = File.new(File.join(File.dirname(__FILE__),
196
+ "fixtures",
197
+ "5k.png"), 'rb')
198
+ @dummyA = Dummy.new(:other => 'a')
199
+ @dummyA.avatar = @file
200
+ @dummyB = Dummy.new(:other => 'b')
201
+ @dummyB.avatar = @file
202
+ end
203
+
204
+ teardown { @file.close }
205
+
206
+ should "return correct path" do
207
+ assert_equal "path/a.png", @dummyA.avatar.path
208
+ assert_equal "path/b.png", @dummyB.avatar.path
209
+ end
210
+ end
211
+
212
+ context "An attachment with :styles that is a proc" do
213
+ setup do
214
+ rebuild_model :styles => lambda{ |attachment| {:thumb => "50x50#", :large => "400x400"} }
215
+
216
+ @attachment = Dummy.new.avatar
217
+ end
218
+
219
+ should "have the correct geometry" do
220
+ assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
221
+ end
222
+ end
223
+
224
+ context "An attachment with :url that is a proc" do
225
+ setup do
226
+ rebuild_model :url => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
227
+
228
+ @file = File.new(File.join(File.dirname(__FILE__),
229
+ "fixtures",
230
+ "5k.png"), 'rb')
231
+ @dummyA = Dummy.new(:other => 'a')
232
+ @dummyA.avatar = @file
233
+ @dummyB = Dummy.new(:other => 'b')
234
+ @dummyB.avatar = @file
235
+ end
236
+
237
+ teardown { @file.close }
238
+
239
+ should "return correct url" do
240
+ assert_equal "path/a.png", @dummyA.avatar.url(:original, false)
241
+ assert_equal "path/b.png", @dummyB.avatar.url(:original, false)
242
+ end
243
+ end
244
+
245
+ geometry_specs = [
246
+ [ lambda{|z| "50x50#" }, :png ],
247
+ lambda{|z| "50x50#" },
248
+ { :geometry => lambda{|z| "50x50#" } }
249
+ ]
250
+ geometry_specs.each do |geometry_spec|
251
+ context "An attachment geometry like #{geometry_spec}" do
252
+ setup do
253
+ rebuild_model :styles => { :normal => geometry_spec }
254
+ @attachment = Dummy.new.avatar
255
+ end
256
+
257
+ should "not run the procs immediately" do
258
+ assert_kind_of Proc, @attachment.styles[:normal][:geometry]
259
+ end
260
+
261
+ context "when assigned" do
262
+ setup do
263
+ @file = StringIO.new(".")
264
+ @attachment.assign(@file)
265
+ end
266
+
267
+ should "have the correct geometry" do
268
+ assert_equal "50x50#", @attachment.styles[:normal][:geometry]
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ context "An attachment with both 'normal' and hash-style styles" do
275
+ setup do
276
+ rebuild_model :styles => {
277
+ :normal => ["50x50#", :png],
278
+ :hash => { :geometry => "50x50#", :format => :png }
279
+ }
280
+ @dummy = Dummy.new
281
+ @attachment = @dummy.avatar
282
+ end
283
+
284
+ [:processors, :whiny, :convert_options, :geometry, :format].each do |field|
285
+ should "have the same #{field} field" do
286
+ assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field]
287
+ end
288
+ end
289
+ end
290
+
291
+ context "An attachment with :processors that is a proc" do
292
+ setup do
293
+ rebuild_model :styles => { :normal => '' }, :processors => lambda { |a| [ :test ] }
294
+ @attachment = Dummy.new.avatar
295
+ end
296
+
297
+ should "not run the proc immediately" do
298
+ assert_kind_of Proc, @attachment.styles[:normal][:processors]
299
+ end
300
+
301
+ context "when assigned" do
302
+ setup do
303
+ @attachment.assign(StringIO.new("."))
304
+ end
305
+
306
+ should "have the correct processors" do
307
+ assert_equal [ :test ], @attachment.styles[:normal][:processors]
308
+ end
309
+ end
310
+ end
311
+
312
+ context "An attachment with erroring processor" do
313
+ setup do
314
+ rebuild_model :processor => [:thumbnail], :styles => { :small => '' }, :whiny_thumbnails => true
315
+ @dummy = Dummy.new
316
+ Paperclip::Thumbnail.expects(:make).raises(Paperclip::PaperclipError, "cannot be processed.")
317
+ @file = StringIO.new("...")
318
+ @file.stubs(:to_tempfile).returns(@file)
319
+ @dummy.avatar = @file
320
+ end
321
+
322
+ should "correctly forward processing error message to the instance" do
323
+ @dummy.valid?
324
+ assert_contains @dummy.errors.full_messages, "Avatar cannot be processed."
325
+ end
326
+ end
327
+
328
+ context "An attachment with multiple processors" do
329
+ setup do
330
+ class Paperclip::Test < Paperclip::Processor; end
331
+ @style_params = { :once => {:one => 1, :two => 2} }
332
+ rebuild_model :processors => [:thumbnail, :test], :styles => @style_params
333
+ @dummy = Dummy.new
334
+ @file = StringIO.new("...")
335
+ @file.stubs(:to_tempfile).returns(@file)
336
+ Paperclip::Test.stubs(:make).returns(@file)
337
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
338
+ end
339
+
340
+ context "when assigned" do
341
+ setup { @dummy.avatar = @file }
342
+
343
+ before_should "call #make on all specified processors" do
344
+ expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""})
345
+ Paperclip::Thumbnail.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file)
346
+ Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file)
347
+ end
348
+
349
+ before_should "call #make with attachment passed as third argument" do
350
+ expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""})
351
+ Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file)
352
+ end
353
+ end
354
+ end
355
+
356
+ context "An attachment with no processors defined" do
357
+ setup do
358
+ rebuild_model :processors => [], :styles => {:something => 1}
359
+ @dummy = Dummy.new
360
+ @file = StringIO.new("...")
361
+ end
362
+ should "raise when assigned to" do
363
+ assert_raises(RuntimeError){ @dummy.avatar = @file }
364
+ end
365
+ end
366
+
367
+ context "Assigning an attachment with post_process hooks" do
368
+ setup do
369
+ rebuild_model :styles => { :something => "100x100#" }
370
+ Dummy.class_eval do
371
+ before_avatar_post_process :do_before_avatar
372
+ after_avatar_post_process :do_after_avatar
373
+ before_post_process :do_before_all
374
+ after_post_process :do_after_all
375
+ def do_before_avatar; end
376
+ def do_after_avatar; end
377
+ def do_before_all; end
378
+ def do_after_all; end
379
+ end
380
+ @file = StringIO.new(".")
381
+ @file.stubs(:to_tempfile).returns(@file)
382
+ @dummy = Dummy.new
383
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
384
+ @attachment = @dummy.avatar
385
+ end
386
+
387
+ should "call the defined callbacks when assigned" do
388
+ @dummy.expects(:do_before_avatar).with()
389
+ @dummy.expects(:do_after_avatar).with()
390
+ @dummy.expects(:do_before_all).with()
391
+ @dummy.expects(:do_after_all).with()
392
+ Paperclip::Thumbnail.expects(:make).returns(@file)
393
+ @dummy.avatar = @file
394
+ end
395
+
396
+ should "not cancel the processing if a before_post_process returns nil" do
397
+ @dummy.expects(:do_before_avatar).with().returns(nil)
398
+ @dummy.expects(:do_after_avatar).with()
399
+ @dummy.expects(:do_before_all).with().returns(nil)
400
+ @dummy.expects(:do_after_all).with()
401
+ Paperclip::Thumbnail.expects(:make).returns(@file)
402
+ @dummy.avatar = @file
403
+ end
404
+
405
+ should "cancel the processing if a before_post_process returns false" do
406
+ @dummy.expects(:do_before_avatar).never
407
+ @dummy.expects(:do_after_avatar).never
408
+ @dummy.expects(:do_before_all).with().returns(false)
409
+ @dummy.expects(:do_after_all).never
410
+ Paperclip::Thumbnail.expects(:make).never
411
+ @dummy.avatar = @file
412
+ end
413
+
414
+ should "cancel the processing if a before_avatar_post_process returns false" do
415
+ @dummy.expects(:do_before_avatar).with().returns(false)
416
+ @dummy.expects(:do_after_avatar).never
417
+ @dummy.expects(:do_before_all).with().returns(true)
418
+ @dummy.expects(:do_after_all).never
419
+ Paperclip::Thumbnail.expects(:make).never
420
+ @dummy.avatar = @file
421
+ end
422
+ end
423
+
424
+ context "Assigning an attachment" do
425
+ setup do
426
+ rebuild_model :styles => { :something => "100x100#" }
427
+ @file = StringIO.new(".")
428
+ @file.expects(:original_filename).returns("5k.png\n\n")
429
+ @file.expects(:content_type).returns("image/png\n\n")
430
+ @file.stubs(:to_tempfile).returns(@file)
431
+ @dummy = Dummy.new
432
+ Paperclip::Thumbnail.expects(:make).returns(@file)
433
+ @dummy.expects(:run_callbacks).with(:before_avatar_post_process, {:original => @file})
434
+ @dummy.expects(:run_callbacks).with(:before_post_process, {:original => @file})
435
+ @dummy.expects(:run_callbacks).with(:after_avatar_post_process, {:original => @file, :something => @file})
436
+ @dummy.expects(:run_callbacks).with(:after_post_process, {:original => @file, :something => @file})
437
+ @attachment = @dummy.avatar
438
+ @dummy.avatar = @file
439
+ end
440
+
441
+ should "strip whitespace from original_filename field" do
442
+ assert_equal "5k.png", @dummy.avatar.original_filename
443
+ end
444
+
445
+ should "strip whitespace from content_type field" do
446
+ assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
447
+ end
448
+ end
449
+
450
+ context "Attachment with strange letters" do
451
+ setup do
452
+ rebuild_model
453
+
454
+ @not_file = mock
455
+ @tempfile = mock
456
+ @not_file.stubs(:nil?).returns(false)
457
+ @not_file.expects(:size).returns(10)
458
+ @tempfile.expects(:size).returns(10)
459
+ @not_file.expects(:to_tempfile).returns(@tempfile)
460
+ @not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n")
461
+ @not_file.expects(:content_type).returns("image/png\r\n")
462
+
463
+ @dummy = Dummy.new
464
+ @attachment = @dummy.avatar
465
+ @attachment.expects(:valid_assignment?).with(@not_file).returns(true)
466
+ @attachment.expects(:queue_existing_for_delete)
467
+ @attachment.expects(:post_process)
468
+ @attachment.expects(:valid?).returns(true)
469
+ @attachment.expects(:validate)
470
+ @dummy.avatar = @not_file
471
+ end
472
+
473
+ should "remove strange letters and replace with underscore (_)" do
474
+ assert_equal "sheep_say_b_.png", @dummy.avatar.original_filename
475
+ end
476
+
477
+ end
478
+
479
+ context "An attachment" do
480
+ setup do
481
+ @old_defaults = Paperclip::Attachment.default_options.dup
482
+ Paperclip::Attachment.default_options.merge!({
483
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
484
+ })
485
+ FileUtils.rm_rf("tmp")
486
+ rebuild_model
487
+ @instance = Dummy.new
488
+ @attachment = Paperclip::Attachment.new(:avatar, @instance)
489
+ @file = File.new(File.join(File.dirname(__FILE__),
490
+ "fixtures",
491
+ "5k.png"), 'rb')
492
+ end
493
+
494
+ teardown do
495
+ @file.close
496
+ Paperclip::Attachment.default_options.merge!(@old_defaults)
497
+ end
498
+
499
+ should "raise if there are not the correct columns when you try to assign" do
500
+ @other_attachment = Paperclip::Attachment.new(:not_here, @instance)
501
+ assert_raises(Paperclip::PaperclipError) do
502
+ @other_attachment.assign(@file)
503
+ end
504
+ end
505
+
506
+ should "return its default_url when no file assigned" do
507
+ assert @attachment.to_file.nil?
508
+ assert_equal "/avatars/original/missing.png", @attachment.url
509
+ assert_equal "/avatars/blah/missing.png", @attachment.url(:blah)
510
+ end
511
+
512
+ should "return nil as path when no file assigned" do
513
+ assert @attachment.to_file.nil?
514
+ assert_equal nil, @attachment.path
515
+ assert_equal nil, @attachment.path(:blah)
516
+ end
517
+
518
+ context "with a file assigned in the database" do
519
+ setup do
520
+ @attachment.stubs(:instance_read).with(:file_name).returns("5k.png")
521
+ @attachment.stubs(:instance_read).with(:content_type).returns("image/png")
522
+ @attachment.stubs(:instance_read).with(:file_size).returns(12345)
523
+ now = Time.now
524
+ Time.stubs(:now).returns(now)
525
+ @attachment.stubs(:instance_read).with(:updated_at).returns(Time.now)
526
+ end
527
+
528
+ should "return a correct url even if the file does not exist" do
529
+ assert_nil @attachment.to_file
530
+ assert_match %r{^/system/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
531
+ end
532
+
533
+ should "make sure the updated_at mtime is in the url if it is defined" do
534
+ assert_match %r{#{Time.now.to_i}$}, @attachment.url(:blah)
535
+ end
536
+
537
+ should "make sure the updated_at mtime is NOT in the url if false is passed to the url method" do
538
+ assert_no_match %r{#{Time.now.to_i}$}, @attachment.url(:blah, false)
539
+ end
540
+
541
+ context "with the updated_at field removed" do
542
+ setup do
543
+ @attachment.stubs(:instance_read).with(:updated_at).returns(nil)
544
+ end
545
+
546
+ should "only return the url without the updated_at when sent #url" do
547
+ assert_match "/avatars/#{@instance.id}/blah/5k.png", @attachment.url(:blah)
548
+ end
549
+ end
550
+
551
+ should "return the proper path when filename has a single .'s" do
552
+ assert_equal "./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.png", @attachment.path
553
+ end
554
+
555
+ should "return the proper path when filename has multiple .'s" do
556
+ @attachment.stubs(:instance_read).with(:file_name).returns("5k.old.png")
557
+ assert_equal "./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png", @attachment.path
558
+ end
559
+
560
+ context "when expecting three styles" do
561
+ setup do
562
+ styles = {:styles => { :large => ["400x400", :png],
563
+ :medium => ["100x100", :gif],
564
+ :small => ["32x32#", :jpg]}}
565
+ @attachment = Paperclip::Attachment.new(:avatar,
566
+ @instance,
567
+ styles)
568
+ end
569
+
570
+ context "and assigned a file" do
571
+ setup do
572
+ now = Time.now
573
+ Time.stubs(:now).returns(now)
574
+ @attachment.assign(@file)
575
+ end
576
+
577
+ should "be dirty" do
578
+ assert @attachment.dirty?
579
+ end
580
+
581
+ context "and saved" do
582
+ setup do
583
+ @attachment.save
584
+ end
585
+
586
+ should "return the real url" do
587
+ file = @attachment.to_file
588
+ assert file
589
+ assert_match %r{^/system/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
590
+ assert_match %r{^/system/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
591
+ file.close
592
+ end
593
+
594
+ should "commit the files to disk" do
595
+ [:large, :medium, :small].each do |style|
596
+ io = @attachment.to_io(style)
597
+ assert File.exists?(io)
598
+ assert ! io.is_a?(::Tempfile)
599
+ io.close
600
+ end
601
+ end
602
+
603
+ should "save the files as the right formats and sizes" do
604
+ [[:large, 400, 61, "PNG"],
605
+ [:medium, 100, 15, "GIF"],
606
+ [:small, 32, 32, "JPEG"]].each do |style|
607
+ cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"]
608
+ out = `#{cmd}`
609
+ width, height, size, format = out.split(" ")
610
+ assert_equal style[1].to_s, width.to_s
611
+ assert_equal style[2].to_s, height.to_s
612
+ assert_equal style[3].to_s, format.to_s
613
+ end
614
+ end
615
+
616
+ should "still have its #file attribute not be nil" do
617
+ assert ! (file = @attachment.to_file).nil?
618
+ file.close
619
+ end
620
+
621
+ context "and trying to delete" do
622
+ setup do
623
+ @existing_names = @attachment.styles.keys.collect do |style|
624
+ @attachment.path(style)
625
+ end
626
+ end
627
+
628
+ should "delete the files after assigning nil" do
629
+ @attachment.expects(:instance_write).with(:file_name, nil)
630
+ @attachment.expects(:instance_write).with(:content_type, nil)
631
+ @attachment.expects(:instance_write).with(:file_size, nil)
632
+ @attachment.expects(:instance_write).with(:updated_at, nil)
633
+ @attachment.assign nil
634
+ @attachment.save
635
+ @existing_names.each{|f| assert ! File.exists?(f) }
636
+ end
637
+
638
+ should "delete the files when you call #clear and #save" do
639
+ @attachment.expects(:instance_write).with(:file_name, nil)
640
+ @attachment.expects(:instance_write).with(:content_type, nil)
641
+ @attachment.expects(:instance_write).with(:file_size, nil)
642
+ @attachment.expects(:instance_write).with(:updated_at, nil)
643
+ @attachment.clear
644
+ @attachment.save
645
+ @existing_names.each{|f| assert ! File.exists?(f) }
646
+ end
647
+
648
+ should "delete the files when you call #delete" do
649
+ @attachment.expects(:instance_write).with(:file_name, nil)
650
+ @attachment.expects(:instance_write).with(:content_type, nil)
651
+ @attachment.expects(:instance_write).with(:file_size, nil)
652
+ @attachment.expects(:instance_write).with(:updated_at, nil)
653
+ @attachment.destroy
654
+ @existing_names.each{|f| assert ! File.exists?(f) }
655
+ end
656
+ end
657
+ end
658
+ end
659
+ end
660
+
661
+ end
662
+
663
+ context "when trying a nonexistant storage type" do
664
+ setup do
665
+ rebuild_model :storage => :not_here
666
+ end
667
+
668
+ should "not be able to find the module" do
669
+ assert_raise(NameError){ Dummy.new.avatar }
670
+ end
671
+ end
672
+ end
673
+
674
+ context "An attachment with only a avatar_file_name column" do
675
+ setup do
676
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
677
+ table.column :avatar_file_name, :string
678
+ end
679
+ rebuild_class
680
+ @dummy = Dummy.new
681
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
682
+ end
683
+
684
+ teardown { @file.close }
685
+
686
+ should "not error when assigned an attachment" do
687
+ assert_nothing_raised { @dummy.avatar = @file }
688
+ end
689
+
690
+ should "return the time when sent #avatar_updated_at" do
691
+ now = Time.now
692
+ Time.stubs(:now).returns(now)
693
+ @dummy.avatar = @file
694
+ assert now, @dummy.avatar.updated_at
695
+ end
696
+
697
+ should "return nil when reloaded and sent #avatar_updated_at" do
698
+ @dummy.save
699
+ @dummy.reload
700
+ assert_nil @dummy.avatar.updated_at
701
+ end
702
+
703
+ should "return the right value when sent #avatar_file_size" do
704
+ @dummy.avatar = @file
705
+ assert_equal @file.size, @dummy.avatar.size
706
+ end
707
+
708
+ context "and avatar_updated_at column" do
709
+ setup do
710
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_updated_at, :timestamp
711
+ rebuild_class
712
+ @dummy = Dummy.new
713
+ end
714
+
715
+ should "not error when assigned an attachment" do
716
+ assert_nothing_raised { @dummy.avatar = @file }
717
+ end
718
+
719
+ should "return the right value when sent #avatar_updated_at" do
720
+ now = Time.now
721
+ Time.stubs(:now).returns(now)
722
+ @dummy.avatar = @file
723
+ assert_equal now.to_i, @dummy.avatar.updated_at
724
+ end
725
+ end
726
+
727
+ context "and avatar_content_type column" do
728
+ setup do
729
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string
730
+ rebuild_class
731
+ @dummy = Dummy.new
732
+ end
733
+
734
+ should "not error when assigned an attachment" do
735
+ assert_nothing_raised { @dummy.avatar = @file }
736
+ end
737
+
738
+ should "return the right value when sent #avatar_content_type" do
739
+ @dummy.avatar = @file
740
+ assert_equal "image/png", @dummy.avatar.content_type
741
+ end
742
+ end
743
+
744
+ context "and avatar_file_size column" do
745
+ setup do
746
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer
747
+ rebuild_class
748
+ @dummy = Dummy.new
749
+ end
750
+
751
+ should "not error when assigned an attachment" do
752
+ assert_nothing_raised { @dummy.avatar = @file }
753
+ end
754
+
755
+ should "return the right value when sent #avatar_file_size" do
756
+ @dummy.avatar = @file
757
+ assert_equal @file.size, @dummy.avatar.size
758
+ end
759
+
760
+ should "return the right value when saved, reloaded, and sent #avatar_file_size" do
761
+ @dummy.avatar = @file
762
+ @dummy.save
763
+ @dummy = Dummy.find(@dummy.id)
764
+ assert_equal @file.size, @dummy.avatar.size
765
+ end
766
+ end
767
+ end
768
+ end