path-paperclip 2.3.3

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