paperclip-hacked 2.3.1.1

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