path-paperclip 2.3.3

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 (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