cloudfuji_paperclip 2.4.6

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 (105) hide show
  1. data/.gitignore +22 -0
  2. data/.travis.yml +13 -0
  3. data/Appraisals +14 -0
  4. data/CONTRIBUTING.md +38 -0
  5. data/Gemfile +5 -0
  6. data/Gemfile.lock +137 -0
  7. data/LICENSE +26 -0
  8. data/README.md +444 -0
  9. data/Rakefile +41 -0
  10. data/cucumber/paperclip_steps.rb +6 -0
  11. data/features/basic_integration.feature +46 -0
  12. data/features/rake_tasks.feature +63 -0
  13. data/features/step_definitions/attachment_steps.rb +65 -0
  14. data/features/step_definitions/html_steps.rb +15 -0
  15. data/features/step_definitions/rails_steps.rb +182 -0
  16. data/features/step_definitions/s3_steps.rb +14 -0
  17. data/features/step_definitions/web_steps.rb +209 -0
  18. data/features/support/env.rb +8 -0
  19. data/features/support/fakeweb.rb +3 -0
  20. data/features/support/fixtures/.boot_config.rb.swo +0 -0
  21. data/features/support/fixtures/boot_config.txt +15 -0
  22. data/features/support/fixtures/gemfile.txt +5 -0
  23. data/features/support/fixtures/preinitializer.txt +20 -0
  24. data/features/support/paths.rb +28 -0
  25. data/features/support/rails.rb +46 -0
  26. data/features/support/selectors.rb +19 -0
  27. data/gemfiles/rails2.gemfile +9 -0
  28. data/gemfiles/rails3.gemfile +9 -0
  29. data/gemfiles/rails3_1.gemfile +9 -0
  30. data/generators/paperclip/USAGE +5 -0
  31. data/generators/paperclip/paperclip_generator.rb +27 -0
  32. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  33. data/init.rb +4 -0
  34. data/lib/generators/paperclip/USAGE +8 -0
  35. data/lib/generators/paperclip/paperclip_generator.rb +33 -0
  36. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  37. data/lib/paperclip/attachment.rb +468 -0
  38. data/lib/paperclip/callback_compatibility.rb +61 -0
  39. data/lib/paperclip/geometry.rb +120 -0
  40. data/lib/paperclip/interpolations.rb +174 -0
  41. data/lib/paperclip/iostream.rb +45 -0
  42. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  43. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
  44. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  45. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  46. data/lib/paperclip/matchers.rb +64 -0
  47. data/lib/paperclip/missing_attachment_styles.rb +87 -0
  48. data/lib/paperclip/processor.rb +58 -0
  49. data/lib/paperclip/railtie.rb +31 -0
  50. data/lib/paperclip/schema.rb +39 -0
  51. data/lib/paperclip/storage/filesystem.rb +81 -0
  52. data/lib/paperclip/storage/fog.rb +174 -0
  53. data/lib/paperclip/storage/s3.rb +333 -0
  54. data/lib/paperclip/storage.rb +3 -0
  55. data/lib/paperclip/style.rb +103 -0
  56. data/lib/paperclip/thumbnail.rb +105 -0
  57. data/lib/paperclip/upfile.rb +62 -0
  58. data/lib/paperclip/url_generator.rb +64 -0
  59. data/lib/paperclip/version.rb +3 -0
  60. data/lib/paperclip.rb +487 -0
  61. data/lib/tasks/paperclip.rake +101 -0
  62. data/paperclip.gemspec +41 -0
  63. data/rails/init.rb +2 -0
  64. data/shoulda_macros/paperclip.rb +124 -0
  65. data/test/.gitignore +1 -0
  66. data/test/attachment_test.rb +1116 -0
  67. data/test/database.yml +4 -0
  68. data/test/fixtures/12k.png +0 -0
  69. data/test/fixtures/50x50.png +0 -0
  70. data/test/fixtures/5k.png +0 -0
  71. data/test/fixtures/animated.gif +0 -0
  72. data/test/fixtures/bad.png +1 -0
  73. data/test/fixtures/fog.yml +8 -0
  74. data/test/fixtures/question?mark.png +0 -0
  75. data/test/fixtures/s3.yml +8 -0
  76. data/test/fixtures/spaced file.png +0 -0
  77. data/test/fixtures/text.txt +1 -0
  78. data/test/fixtures/twopage.pdf +0 -0
  79. data/test/fixtures/uppercase.PNG +0 -0
  80. data/test/geometry_test.rb +206 -0
  81. data/test/helper.rb +177 -0
  82. data/test/integration_test.rb +654 -0
  83. data/test/interpolations_test.rb +216 -0
  84. data/test/iostream_test.rb +71 -0
  85. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  86. data/test/matchers/validate_attachment_content_type_matcher_test.rb +87 -0
  87. data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
  88. data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
  89. data/test/paperclip_missing_attachment_styles_test.rb +80 -0
  90. data/test/paperclip_test.rb +390 -0
  91. data/test/processor_test.rb +10 -0
  92. data/test/schema_test.rb +98 -0
  93. data/test/storage/filesystem_test.rb +56 -0
  94. data/test/storage/fog_test.rb +219 -0
  95. data/test/storage/s3_live_test.rb +138 -0
  96. data/test/storage/s3_test.rb +943 -0
  97. data/test/style_test.rb +209 -0
  98. data/test/support/mock_attachment.rb +22 -0
  99. data/test/support/mock_interpolator.rb +24 -0
  100. data/test/support/mock_model.rb +2 -0
  101. data/test/support/mock_url_generator_builder.rb +27 -0
  102. data/test/thumbnail_test.rb +383 -0
  103. data/test/upfile_test.rb +53 -0
  104. data/test/url_generator_test.rb +187 -0
  105. metadata +404 -0
@@ -0,0 +1,1116 @@
1
+ # encoding: utf-8
2
+ require './test/helper'
3
+ require 'paperclip/attachment'
4
+
5
+ class Dummy; end
6
+
7
+ class AttachmentTest < Test::Unit::TestCase
8
+ should "handle a boolean second argument to #url" do
9
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
10
+ attachment = Paperclip::Attachment.new(:name, :instance, :url_generator => mock_url_generator_builder)
11
+
12
+ attachment.url(:style_name, true)
13
+ assert mock_url_generator_builder.has_generated_url_with_options?(:timestamp => true, :escape => true)
14
+
15
+ attachment.url(:style_name, false)
16
+ assert mock_url_generator_builder.has_generated_url_with_options?(:timestamp => false, :escape => true)
17
+ end
18
+
19
+ should "pass the style and options through to the URL generator on #url" do
20
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
21
+ attachment = Paperclip::Attachment.new(:name, :instance, :url_generator => mock_url_generator_builder)
22
+
23
+ attachment.url(:style_name, :options => :values)
24
+ assert mock_url_generator_builder.has_generated_url_with_options?(:options => :values)
25
+ end
26
+
27
+ should "pass default options through when #url is given one argument" do
28
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
29
+ attachment = Paperclip::Attachment.new(:name,
30
+ :instance,
31
+ :url_generator => mock_url_generator_builder,
32
+ :use_timestamp => true)
33
+
34
+ attachment.url(:style_name)
35
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true, :timestamp => true)
36
+ end
37
+
38
+ should "pass default style and options through when #url is given no arguments" do
39
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
40
+ attachment = Paperclip::Attachment.new(:name,
41
+ :instance,
42
+ :default_style => 'default style',
43
+ :url_generator => mock_url_generator_builder,
44
+ :use_timestamp => true)
45
+
46
+ attachment.url
47
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true, :timestamp => true)
48
+ assert mock_url_generator_builder.has_generated_url_with_style_name?('default style')
49
+ end
50
+
51
+ should "pass the option :timestamp => true if :use_timestamp is true and :timestamp is not passed" do
52
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
53
+ attachment = Paperclip::Attachment.new(:name,
54
+ :instance,
55
+ :url_generator => mock_url_generator_builder,
56
+ :use_timestamp => true)
57
+
58
+ attachment.url(:style_name)
59
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true, :timestamp => true)
60
+ end
61
+
62
+ should "pass the option :timestamp => false if :use_timestamp is false and :timestamp is not passed" do
63
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
64
+ attachment = Paperclip::Attachment.new(:name,
65
+ :instance,
66
+ :url_generator => mock_url_generator_builder,
67
+ :use_timestamp => false)
68
+
69
+ attachment.url(:style_name)
70
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true, :timestamp => false)
71
+ end
72
+
73
+ should "not change the :timestamp if :timestamp is passed" do
74
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
75
+ attachment = Paperclip::Attachment.new(:name,
76
+ :instance,
77
+ :url_generator => mock_url_generator_builder,
78
+ :use_timestamp => false)
79
+
80
+ attachment.url(:style_name, :timestamp => true)
81
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true, :timestamp => true)
82
+ end
83
+
84
+ should "return the path based on the url by default" do
85
+ @attachment = attachment :url => "/:class/:id/:basename"
86
+ @model = @attachment.instance
87
+ @model.id = 1234
88
+ @model.avatar_file_name = "fake.jpg"
89
+ assert_equal "#{Rails.root}/public/fake_models/1234/fake", @attachment.path
90
+ end
91
+
92
+ context "Attachment default_options" do
93
+ setup do
94
+ rebuild_model
95
+ @old_default_options = Paperclip::Attachment.default_options.dup
96
+ @new_default_options = @old_default_options.merge({
97
+ :path => "argle/bargle",
98
+ :url => "fooferon",
99
+ :default_url => "not here.png"
100
+ })
101
+ end
102
+
103
+ teardown do
104
+ Paperclip::Attachment.default_options.merge! @old_default_options
105
+ end
106
+
107
+ should "be overrideable" do
108
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
109
+ @new_default_options.keys.each do |key|
110
+ assert_equal @new_default_options[key],
111
+ Paperclip::Attachment.default_options[key]
112
+ end
113
+ end
114
+
115
+ context "without an Attachment" do
116
+ setup do
117
+ @dummy = Dummy.new
118
+ end
119
+
120
+ should "return false when asked exists?" do
121
+ assert !@dummy.avatar.exists?
122
+ end
123
+ end
124
+
125
+ context "on an Attachment" do
126
+ setup do
127
+ @dummy = Dummy.new
128
+ @attachment = @dummy.avatar
129
+ end
130
+
131
+ Paperclip::Attachment.default_options.keys.each do |key|
132
+ should "be the default_options for #{key}" do
133
+ assert_equal @old_default_options[key],
134
+ @attachment.instance_variable_get("@options")[key],
135
+ key
136
+ end
137
+ end
138
+
139
+ context "when redefined" do
140
+ setup do
141
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
142
+ @dummy = Dummy.new
143
+ @attachment = @dummy.avatar
144
+ end
145
+
146
+ Paperclip::Attachment.default_options.keys.each do |key|
147
+ should "be the new default_options for #{key}" do
148
+ assert_equal @new_default_options[key],
149
+ @attachment.instance_variable_get("@options")[key],
150
+ key
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ context "An attachment with similarly named interpolations" do
158
+ setup do
159
+ rebuild_model :path => ":id.omg/:id-bbq/:idwhat/:id_partition.wtf"
160
+ @dummy = Dummy.new
161
+ @dummy.stubs(:id).returns(1024)
162
+ @file = File.new(File.join(File.dirname(__FILE__),
163
+ "fixtures",
164
+ "5k.png"), 'rb')
165
+ @dummy.avatar = @file
166
+ end
167
+
168
+ teardown { @file.close }
169
+
170
+ should "make sure that they are interpolated correctly" do
171
+ assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path
172
+ end
173
+ end
174
+
175
+ context "An attachment with :timestamp interpolations" do
176
+ setup do
177
+ @file = StringIO.new("...")
178
+ @zone = 'UTC'
179
+ Time.stubs(:zone).returns(@zone)
180
+ @zone_default = 'Eastern Time (US & Canada)'
181
+ Time.stubs(:zone_default).returns(@zone_default)
182
+ end
183
+
184
+ context "using default time zone" do
185
+ setup do
186
+ rebuild_model :path => ":timestamp", :use_default_time_zone => true
187
+ @dummy = Dummy.new
188
+ @dummy.avatar = @file
189
+ end
190
+
191
+ should "return a time in the default zone" do
192
+ assert_equal @dummy.avatar_updated_at.in_time_zone(@zone_default).to_s, @dummy.avatar.path
193
+ end
194
+ end
195
+
196
+ context "using per-thread time zone" do
197
+ setup do
198
+ rebuild_model :path => ":timestamp", :use_default_time_zone => false
199
+ @dummy = Dummy.new
200
+ @dummy.avatar = @file
201
+ end
202
+
203
+ should "return a time in the per-thread zone" do
204
+ assert_equal @dummy.avatar_updated_at.in_time_zone(@zone).to_s, @dummy.avatar.path
205
+ end
206
+ end
207
+ end
208
+
209
+ context "An attachment with :hash interpolations" do
210
+ setup do
211
+ @file = StringIO.new("...")
212
+ end
213
+
214
+ should "raise if no secret is provided" do
215
+ @attachment = attachment :path => ":hash"
216
+ @attachment.assign @file
217
+
218
+ assert_raise ArgumentError do
219
+ @attachment.path
220
+ end
221
+ end
222
+
223
+ context "when secret is set" do
224
+ setup do
225
+ @attachment = attachment :path => ":hash", :hash_secret => "w00t"
226
+ @attachment.stubs(:instance_read).with(:updated_at).returns(Time.at(1234567890))
227
+ @attachment.stubs(:instance_read).with(:file_name).returns("bla.txt")
228
+ @attachment.instance.id = 1234
229
+ @attachment.assign @file
230
+ end
231
+
232
+ should "interpolate the hash data" do
233
+ @attachment.expects(:interpolate).with(@attachment.options[:hash_data],anything).returns("interpolated_stuff")
234
+ @attachment.hash
235
+ end
236
+
237
+ should "result in the correct interpolation" do
238
+ assert_equal "fake_models/avatars/1234/original/1234567890", @attachment.send(:interpolate,@attachment.options[:hash_data])
239
+ end
240
+
241
+ should "result in a correct hash" do
242
+ assert_equal "d22b617d1bf10016aa7d046d16427ae203f39fce", @attachment.path
243
+ end
244
+
245
+ should "generate a hash digest with the correct style" do
246
+ OpenSSL::HMAC.expects(:hexdigest).with(anything, anything, "fake_models/avatars/1234/medium/1234567890")
247
+ @attachment.path("medium")
248
+ end
249
+ end
250
+ end
251
+
252
+ context "An attachment with a :rails_env interpolation" do
253
+ setup do
254
+ @rails_env = "blah"
255
+ @id = 1024
256
+ rebuild_model :path => ":rails_env/:id.png"
257
+ @dummy = Dummy.new
258
+ @dummy.stubs(:id).returns(@id)
259
+ @file = StringIO.new(".")
260
+ @dummy.avatar = @file
261
+ Rails.stubs(:env).returns(@rails_env)
262
+ end
263
+
264
+ should "return the proper path" do
265
+ assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path
266
+ end
267
+ end
268
+
269
+ context "An attachment with a default style and an extension interpolation" do
270
+ setup do
271
+ @attachment = attachment :path => ":basename.:extension",
272
+ :styles => { :default => ["100x100", :png] },
273
+ :default_style => :default
274
+ @file = StringIO.new("...")
275
+ @file.stubs(:original_filename).returns("file.jpg")
276
+ end
277
+ should "return the right extension for the path" do
278
+ @attachment.assign(@file)
279
+ assert_equal "file.png", @attachment.path
280
+ end
281
+ end
282
+
283
+ context "An attachment with :convert_options" do
284
+ setup do
285
+ rebuild_model :styles => {
286
+ :thumb => "100x100",
287
+ :large => "400x400"
288
+ },
289
+ :convert_options => {
290
+ :all => "-do_stuff",
291
+ :thumb => "-thumbnailize"
292
+ }
293
+ @dummy = Dummy.new
294
+ @dummy.avatar
295
+ end
296
+
297
+ should "report the correct options when sent #extra_options_for(:thumb)" do
298
+ assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
299
+ end
300
+
301
+ should "report the correct options when sent #extra_options_for(:large)" do
302
+ assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
303
+ end
304
+ end
305
+
306
+ context "An attachment with :source_file_options" do
307
+ setup do
308
+ rebuild_model :styles => {
309
+ :thumb => "100x100",
310
+ :large => "400x400"
311
+ },
312
+ :source_file_options => {
313
+ :all => "-density 400",
314
+ :thumb => "-depth 8"
315
+ }
316
+ @dummy = Dummy.new
317
+ @dummy.avatar
318
+ end
319
+
320
+ should "report the correct options when sent #extra_source_file_options_for(:thumb)" do
321
+ assert_equal "-depth 8 -density 400", @dummy.avatar.send(:extra_source_file_options_for, :thumb), @dummy.avatar.source_file_options.inspect
322
+ end
323
+
324
+ should "report the correct options when sent #extra_source_file_options_for(:large)" do
325
+ assert_equal "-density 400", @dummy.avatar.send(:extra_source_file_options_for, :large)
326
+ end
327
+ end
328
+
329
+ context "An attachment with :only_process" do
330
+ setup do
331
+ rebuild_model :styles => {
332
+ :thumb => "100x100",
333
+ :large => "400x400"
334
+ },
335
+ :only_process => [:thumb]
336
+ @file = StringIO.new("...")
337
+ @attachment = Dummy.new.avatar
338
+ end
339
+
340
+ should "only process the provided style" do
341
+ @attachment.expects(:post_process).with(:thumb)
342
+ @attachment.expects(:post_process).with(:large).never
343
+ @attachment.assign(@file)
344
+ end
345
+ end
346
+
347
+ context "An attachment with :convert_options that is a proc" do
348
+ setup do
349
+ rebuild_model :styles => {
350
+ :thumb => "100x100",
351
+ :large => "400x400"
352
+ },
353
+ :convert_options => {
354
+ :all => lambda{|i| i.all },
355
+ :thumb => lambda{|i| i.thumb }
356
+ }
357
+ Dummy.class_eval do
358
+ def all; "-all"; end
359
+ def thumb; "-thumb"; end
360
+ end
361
+ @dummy = Dummy.new
362
+ @dummy.avatar
363
+ end
364
+
365
+ should "report the correct options when sent #extra_options_for(:thumb)" do
366
+ assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
367
+ end
368
+
369
+ should "report the correct options when sent #extra_options_for(:large)" do
370
+ assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
371
+ end
372
+ end
373
+
374
+ context "An attachment with :path that is a proc" do
375
+ setup do
376
+ rebuild_model :path => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
377
+
378
+ @file = File.new(File.join(File.dirname(__FILE__),
379
+ "fixtures",
380
+ "5k.png"), 'rb')
381
+ @dummyA = Dummy.new(:other => 'a')
382
+ @dummyA.avatar = @file
383
+ @dummyB = Dummy.new(:other => 'b')
384
+ @dummyB.avatar = @file
385
+ end
386
+
387
+ teardown { @file.close }
388
+
389
+ should "return correct path" do
390
+ assert_equal "path/a.png", @dummyA.avatar.path
391
+ assert_equal "path/b.png", @dummyB.avatar.path
392
+ end
393
+ end
394
+
395
+ context "An attachment with :styles that is a proc" do
396
+ setup do
397
+ rebuild_model :styles => lambda{ |attachment| {:thumb => "50x50#", :large => "400x400"} }
398
+
399
+ @attachment = Dummy.new.avatar
400
+ end
401
+
402
+ should "have the correct geometry" do
403
+ assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
404
+ end
405
+ end
406
+
407
+ context "An attachment with conditional :styles that is a proc" do
408
+ setup do
409
+ rebuild_model :styles => lambda{ |attachment| attachment.instance.other == 'a' ? {:thumb => "50x50#"} : {:large => "400x400"} }
410
+
411
+ @dummy = Dummy.new(:other => 'a')
412
+ end
413
+
414
+ should "have the correct styles for the assigned instance values" do
415
+ assert_equal "50x50#", @dummy.avatar.styles[:thumb][:geometry]
416
+ assert_nil @dummy.avatar.styles[:large]
417
+
418
+ @dummy.other = 'b'
419
+
420
+ assert_equal "400x400", @dummy.avatar.styles[:large][:geometry]
421
+ assert_nil @dummy.avatar.styles[:thumb]
422
+ end
423
+ end
424
+
425
+ geometry_specs = [
426
+ [ lambda{|z| "50x50#" }, :png ],
427
+ lambda{|z| "50x50#" },
428
+ { :geometry => lambda{|z| "50x50#" } }
429
+ ]
430
+ geometry_specs.each do |geometry_spec|
431
+ context "An attachment geometry like #{geometry_spec}" do
432
+ setup do
433
+ rebuild_model :styles => { :normal => geometry_spec }
434
+ @attachment = Dummy.new.avatar
435
+ end
436
+
437
+ context "when assigned" do
438
+ setup do
439
+ @file = StringIO.new(".")
440
+ @attachment.assign(@file)
441
+ end
442
+
443
+ should "have the correct geometry" do
444
+ assert_equal "50x50#", @attachment.styles[:normal][:geometry]
445
+ end
446
+ end
447
+ end
448
+ end
449
+
450
+ context "An attachment with both 'normal' and hash-style styles" do
451
+ setup do
452
+ rebuild_model :styles => {
453
+ :normal => ["50x50#", :png],
454
+ :hash => { :geometry => "50x50#", :format => :png }
455
+ }
456
+ @dummy = Dummy.new
457
+ @attachment = @dummy.avatar
458
+ end
459
+
460
+ [:processors, :whiny, :convert_options, :geometry, :format].each do |field|
461
+ should "have the same #{field} field" do
462
+ assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field]
463
+ end
464
+ end
465
+ end
466
+
467
+ context "An attachment with :processors that is a proc" do
468
+ setup do
469
+ class Paperclip::Test < Paperclip::Processor; end
470
+ @file = StringIO.new("...")
471
+ Paperclip::Test.stubs(:make).returns(@file)
472
+
473
+ rebuild_model :styles => { :normal => '' }, :processors => lambda { |a| [ :test ] }
474
+ @attachment = Dummy.new.avatar
475
+ end
476
+
477
+ context "when assigned" do
478
+ setup do
479
+ @attachment.assign(StringIO.new("."))
480
+ end
481
+
482
+ should "have the correct processors" do
483
+ assert_equal [ :test ], @attachment.styles[:normal][:processors]
484
+ end
485
+ end
486
+ end
487
+
488
+ context "An attachment with erroring processor" do
489
+ setup do
490
+ rebuild_model :processor => [:thumbnail], :styles => { :small => '' }, :whiny_thumbnails => true
491
+ @dummy = Dummy.new
492
+ Paperclip::Thumbnail.expects(:make).raises(Paperclip::PaperclipError, "cannot be processed.")
493
+ @file = StringIO.new("...")
494
+ @file.stubs(:to_tempfile).returns(@file)
495
+ @dummy.avatar = @file
496
+ end
497
+
498
+ should "correctly forward processing error message to the instance" do
499
+ @dummy.valid?
500
+ assert_contains @dummy.errors.full_messages, "Avatar cannot be processed."
501
+ end
502
+ end
503
+
504
+ context "An attachment with multiple processors" do
505
+ setup do
506
+ class Paperclip::Test < Paperclip::Processor; end
507
+ @style_params = { :once => {:one => 1, :two => 2} }
508
+ rebuild_model :processors => [:thumbnail, :test], :styles => @style_params
509
+ @dummy = Dummy.new
510
+ @file = StringIO.new("...")
511
+ @file.stubs(:to_tempfile).returns(@file)
512
+ Paperclip::Test.stubs(:make).returns(@file)
513
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
514
+ end
515
+
516
+ context "when assigned" do
517
+ setup { @dummy.avatar = @file }
518
+
519
+ before_should "call #make on all specified processors" do
520
+ Paperclip::Thumbnail.expects(:make).with(any_parameters).returns(@file)
521
+ Paperclip::Test.expects(:make).with(any_parameters).returns(@file)
522
+ end
523
+
524
+ before_should "call #make with the right parameters passed as second argument" do
525
+ expected_params = @style_params[:once].merge({
526
+ :processors => [:thumbnail, :test],
527
+ :whiny => true,
528
+ :convert_options => "",
529
+ :source_file_options => ""
530
+ })
531
+ Paperclip::Thumbnail.expects(:make).with(anything, expected_params, anything).returns(@file)
532
+ end
533
+
534
+ before_should "call #make with attachment passed as third argument" do
535
+ Paperclip::Test.expects(:make).with(anything, anything, @dummy.avatar).returns(@file)
536
+ end
537
+ end
538
+ end
539
+
540
+ should "include the filesystem module when loading the filesystem storage" do
541
+ rebuild_model :storage => :filesystem
542
+ @dummy = Dummy.new
543
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
544
+ end
545
+
546
+ should "include the filesystem module even if capitalization is wrong" do
547
+ rebuild_model :storage => :FileSystem
548
+ @dummy = Dummy.new
549
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
550
+
551
+ rebuild_model :storage => :Filesystem
552
+ @dummy = Dummy.new
553
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
554
+ end
555
+
556
+ should "convert underscored storage name to camelcase" do
557
+ rebuild_model :storage => :not_here
558
+ @dummy = Dummy.new
559
+ exception = assert_raises(Paperclip::StorageMethodNotFound) do
560
+ @dummy.avatar
561
+ end
562
+ assert exception.message.include?("NotHere")
563
+ end
564
+
565
+ should "raise an error if you try to include a storage module that doesn't exist" do
566
+ rebuild_model :storage => :not_here
567
+ @dummy = Dummy.new
568
+ assert_raises(Paperclip::StorageMethodNotFound) do
569
+ @dummy.avatar
570
+ end
571
+ end
572
+
573
+ context "An attachment with styles but no processors defined" do
574
+ setup do
575
+ rebuild_model :processors => [], :styles => {:something => '1'}
576
+ @dummy = Dummy.new
577
+ @file = StringIO.new("...")
578
+ end
579
+ should "raise when assigned to" do
580
+ assert_raises(RuntimeError){ @dummy.avatar = @file }
581
+ end
582
+ end
583
+
584
+ context "An attachment without styles and with no processors defined" do
585
+ setup do
586
+ rebuild_model :processors => [], :styles => {}
587
+ @dummy = Dummy.new
588
+ @file = StringIO.new("...")
589
+ end
590
+ should "not raise when assigned to" do
591
+ @dummy.avatar = @file
592
+ end
593
+ end
594
+
595
+ context "Assigning an attachment with post_process hooks" do
596
+ setup do
597
+ rebuild_class :styles => { :something => "100x100#" }
598
+ Dummy.class_eval do
599
+ before_avatar_post_process :do_before_avatar
600
+ after_avatar_post_process :do_after_avatar
601
+ before_post_process :do_before_all
602
+ after_post_process :do_after_all
603
+ def do_before_avatar; end
604
+ def do_after_avatar; end
605
+ def do_before_all; end
606
+ def do_after_all; end
607
+ end
608
+ @file = StringIO.new(".")
609
+ @file.stubs(:to_tempfile).returns(@file)
610
+ @dummy = Dummy.new
611
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
612
+ @attachment = @dummy.avatar
613
+ end
614
+
615
+ should "call the defined callbacks when assigned" do
616
+ @dummy.expects(:do_before_avatar).with()
617
+ @dummy.expects(:do_after_avatar).with()
618
+ @dummy.expects(:do_before_all).with()
619
+ @dummy.expects(:do_after_all).with()
620
+ Paperclip::Thumbnail.expects(:make).returns(@file)
621
+ @dummy.avatar = @file
622
+ end
623
+
624
+ should "not cancel the processing if a before_post_process returns nil" do
625
+ @dummy.expects(:do_before_avatar).with().returns(nil)
626
+ @dummy.expects(:do_after_avatar).with()
627
+ @dummy.expects(:do_before_all).with().returns(nil)
628
+ @dummy.expects(:do_after_all).with()
629
+ Paperclip::Thumbnail.expects(:make).returns(@file)
630
+ @dummy.avatar = @file
631
+ end
632
+
633
+ should "cancel the processing if a before_post_process returns false" do
634
+ @dummy.expects(:do_before_avatar).never
635
+ @dummy.expects(:do_after_avatar).never
636
+ @dummy.expects(:do_before_all).with().returns(false)
637
+ @dummy.expects(:do_after_all)
638
+ Paperclip::Thumbnail.expects(:make).never
639
+ @dummy.avatar = @file
640
+ end
641
+
642
+ should "cancel the processing if a before_avatar_post_process returns false" do
643
+ @dummy.expects(:do_before_avatar).with().returns(false)
644
+ @dummy.expects(:do_after_avatar)
645
+ @dummy.expects(:do_before_all).with().returns(true)
646
+ @dummy.expects(:do_after_all)
647
+ Paperclip::Thumbnail.expects(:make).never
648
+ @dummy.avatar = @file
649
+ end
650
+ end
651
+
652
+ context "Assigning an attachment" do
653
+ setup do
654
+ rebuild_model :styles => { :something => "100x100#" }
655
+ @file = StringIO.new(".")
656
+ @file.stubs(:original_filename).returns("5k.png\n\n")
657
+ @file.stubs(:content_type).returns("image/png\n\n")
658
+ @file.stubs(:to_tempfile).returns(@file)
659
+ @dummy = Dummy.new
660
+ Paperclip::Thumbnail.expects(:make).returns(@file)
661
+ @attachment = @dummy.avatar
662
+ @dummy.avatar = @file
663
+ end
664
+
665
+ should "strip whitespace from original_filename field" do
666
+ assert_equal "5k.png", @dummy.avatar.original_filename
667
+ end
668
+
669
+ should "strip whitespace from content_type field" do
670
+ assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
671
+ end
672
+ end
673
+
674
+ context "Attachment with strange letters" do
675
+ setup do
676
+ rebuild_model
677
+
678
+ @not_file = mock("not_file")
679
+ @tempfile = mock("tempfile")
680
+ @not_file.stubs(:nil?).returns(false)
681
+ @not_file.expects(:size).returns(10)
682
+ @tempfile.expects(:size).returns(10)
683
+ @not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n")
684
+ @not_file.expects(:content_type).returns("image/png\r\n")
685
+
686
+ @dummy = Dummy.new
687
+ @attachment = @dummy.avatar
688
+ @attachment.expects(:valid_assignment?).with(@not_file).returns(true)
689
+ @attachment.expects(:queue_existing_for_delete)
690
+ @attachment.expects(:post_process)
691
+ @attachment.expects(:to_tempfile).returns(@tempfile)
692
+ @attachment.expects(:generate_fingerprint).with(@tempfile).returns("12345")
693
+ @attachment.expects(:generate_fingerprint).with(@not_file).returns("12345")
694
+ @dummy.avatar = @not_file
695
+ end
696
+
697
+ should "not remove strange letters" do
698
+ assert_equal "sheep_say_bæ.png", @dummy.avatar.original_filename
699
+ end
700
+ end
701
+
702
+ context "Attachment with uppercase extension and a default style" do
703
+ setup do
704
+ @old_defaults = Paperclip::Attachment.default_options.dup
705
+ Paperclip::Attachment.default_options.merge!({
706
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
707
+ })
708
+ FileUtils.rm_rf("tmp")
709
+ rebuild_model
710
+ @instance = Dummy.new
711
+ @instance.stubs(:id).returns 123
712
+
713
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "uppercase.PNG"), 'rb')
714
+
715
+ styles = {:styles => { :large => ["400x400", :jpg],
716
+ :medium => ["100x100", :jpg],
717
+ :small => ["32x32#", :jpg]},
718
+ :default_style => :small}
719
+ @attachment = Paperclip::Attachment.new(:avatar,
720
+ @instance,
721
+ styles)
722
+ now = Time.now
723
+ Time.stubs(:now).returns(now)
724
+ @attachment.assign(@file)
725
+ @attachment.save
726
+ end
727
+
728
+ teardown do
729
+ @file.close
730
+ Paperclip::Attachment.default_options.merge!(@old_defaults)
731
+ end
732
+
733
+ should "should have matching to_s and url methods" do
734
+ file = @attachment.to_file
735
+ assert file
736
+ assert_match @attachment.to_s, @attachment.url
737
+ assert_match @attachment.to_s(:small), @attachment.url(:small)
738
+ file.close
739
+ end
740
+ end
741
+
742
+ context "An attachment" do
743
+ setup do
744
+ @old_defaults = Paperclip::Attachment.default_options.dup
745
+ Paperclip::Attachment.default_options.merge!({
746
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
747
+ })
748
+ FileUtils.rm_rf("tmp")
749
+ rebuild_model
750
+ @instance = Dummy.new
751
+ @instance.stubs(:id).returns 123
752
+ @attachment = Paperclip::Attachment.new(:avatar, @instance)
753
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
754
+ end
755
+
756
+ teardown do
757
+ @file.close
758
+ Paperclip::Attachment.default_options.merge!(@old_defaults)
759
+ end
760
+
761
+ should "raise if there are not the correct columns when you try to assign" do
762
+ @other_attachment = Paperclip::Attachment.new(:not_here, @instance)
763
+ assert_raises(Paperclip::PaperclipError) do
764
+ @other_attachment.assign(@file)
765
+ end
766
+ end
767
+
768
+ should "return nil as path when no file assigned" do
769
+ assert @attachment.to_file.nil?
770
+ assert_equal nil, @attachment.path
771
+ assert_equal nil, @attachment.path(:blah)
772
+ end
773
+
774
+ context "with a file assigned but not saved yet" do
775
+ should "clear out any attached files" do
776
+ @attachment.assign(@file)
777
+ assert !@attachment.queued_for_write.blank?
778
+ @attachment.clear
779
+ assert @attachment.queued_for_write.blank?
780
+ end
781
+ end
782
+
783
+ context "with a file assigned in the database" do
784
+ setup do
785
+ @attachment.stubs(:instance_read).with(:file_name).returns("5k.png")
786
+ @attachment.stubs(:instance_read).with(:content_type).returns("image/png")
787
+ @attachment.stubs(:instance_read).with(:file_size).returns(12345)
788
+ dtnow = DateTime.now
789
+ @now = Time.now
790
+ Time.stubs(:now).returns(@now)
791
+ @attachment.stubs(:instance_read).with(:updated_at).returns(dtnow)
792
+ end
793
+
794
+ should "return the proper path when filename has a single .'s" do
795
+ assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.png"), File.expand_path(@attachment.path)
796
+ end
797
+
798
+ should "return the proper path when filename has multiple .'s" do
799
+ @attachment.stubs(:instance_read).with(:file_name).returns("5k.old.png")
800
+ assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png"), File.expand_path(@attachment.path)
801
+ end
802
+
803
+ context "when expecting three styles" do
804
+ setup do
805
+ styles = {:styles => { :large => ["400x400", :png],
806
+ :medium => ["100x100", :gif],
807
+ :small => ["32x32#", :jpg]}}
808
+ @attachment = Paperclip::Attachment.new(:avatar,
809
+ @instance,
810
+ styles)
811
+ end
812
+
813
+ context "and assigned a file" do
814
+ setup do
815
+ now = Time.now
816
+ Time.stubs(:now).returns(now)
817
+ @attachment.assign(@file)
818
+ end
819
+
820
+ should "be dirty" do
821
+ assert @attachment.dirty?
822
+ end
823
+
824
+ should "set uploaded_file for access beyond the paperclip lifecycle" do
825
+ assert_equal @file, @attachment.uploaded_file
826
+ end
827
+
828
+ context "and saved" do
829
+ setup do
830
+ @attachment.save
831
+ end
832
+
833
+ should "commit the files to disk" do
834
+ [:large, :medium, :small].each do |style|
835
+ io = @attachment.to_file(style)
836
+ # p "in commit to disk test, io is #{io.inspect} and @instance.id is #{@instance.id}"
837
+ assert File.exists?(io.path)
838
+ assert ! io.is_a?(::Tempfile)
839
+ io.close
840
+ end
841
+ end
842
+
843
+ should "save the files as the right formats and sizes" do
844
+ [[:large, 400, 61, "PNG"],
845
+ [:medium, 100, 15, "GIF"],
846
+ [:small, 32, 32, "JPEG"]].each do |style|
847
+ cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"]
848
+ out = `#{cmd}`
849
+ width, height, size, format = out.split(" ")
850
+ assert_equal style[1].to_s, width.to_s
851
+ assert_equal style[2].to_s, height.to_s
852
+ assert_equal style[3].to_s, format.to_s
853
+ end
854
+ end
855
+
856
+ should "still have its #file attribute not be nil" do
857
+ assert ! (file = @attachment.to_file).nil?
858
+ file.close
859
+ end
860
+
861
+ context "and trying to delete" do
862
+ setup do
863
+ @existing_names = @attachment.styles.keys.collect do |style|
864
+ @attachment.path(style)
865
+ end
866
+ end
867
+
868
+ should "delete the files after assigning nil" do
869
+ @attachment.expects(:instance_write).with(:file_name, nil)
870
+ @attachment.expects(:instance_write).with(:content_type, nil)
871
+ @attachment.expects(:instance_write).with(:file_size, nil)
872
+ @attachment.expects(:instance_write).with(:updated_at, nil)
873
+ @attachment.assign nil
874
+ @attachment.save
875
+ @existing_names.each{|f| assert ! File.exists?(f) }
876
+ end
877
+
878
+ should "delete the files when you call #clear and #save" do
879
+ @attachment.expects(:instance_write).with(:file_name, nil)
880
+ @attachment.expects(:instance_write).with(:content_type, nil)
881
+ @attachment.expects(:instance_write).with(:file_size, nil)
882
+ @attachment.expects(:instance_write).with(:updated_at, nil)
883
+ @attachment.clear
884
+ @attachment.save
885
+ @existing_names.each{|f| assert ! File.exists?(f) }
886
+ end
887
+
888
+ should "delete the files when you call #delete" do
889
+ @attachment.expects(:instance_write).with(:file_name, nil)
890
+ @attachment.expects(:instance_write).with(:content_type, nil)
891
+ @attachment.expects(:instance_write).with(:file_size, nil)
892
+ @attachment.expects(:instance_write).with(:updated_at, nil)
893
+ @attachment.destroy
894
+ @existing_names.each{|f| assert ! File.exists?(f) }
895
+ end
896
+
897
+ context "when keeping old files" do
898
+ setup do
899
+ @attachment.options[:keep_old_files] = true
900
+ end
901
+
902
+ should "keep the files after assigning nil" do
903
+ @attachment.expects(:instance_write).with(:file_name, nil)
904
+ @attachment.expects(:instance_write).with(:content_type, nil)
905
+ @attachment.expects(:instance_write).with(:file_size, nil)
906
+ @attachment.expects(:instance_write).with(:updated_at, nil)
907
+ @attachment.assign nil
908
+ @attachment.save
909
+ @existing_names.each{|f| assert File.exists?(f) }
910
+ end
911
+
912
+ should "keep the files when you call #clear and #save" do
913
+ @attachment.expects(:instance_write).with(:file_name, nil)
914
+ @attachment.expects(:instance_write).with(:content_type, nil)
915
+ @attachment.expects(:instance_write).with(:file_size, nil)
916
+ @attachment.expects(:instance_write).with(:updated_at, nil)
917
+ @attachment.clear
918
+ @attachment.save
919
+ @existing_names.each{|f| assert File.exists?(f) }
920
+ end
921
+
922
+ should "keep the files when you call #delete" do
923
+ @attachment.expects(:instance_write).with(:file_name, nil)
924
+ @attachment.expects(:instance_write).with(:content_type, nil)
925
+ @attachment.expects(:instance_write).with(:file_size, nil)
926
+ @attachment.expects(:instance_write).with(:updated_at, nil)
927
+ @attachment.destroy
928
+ @existing_names.each{|f| assert File.exists?(f) }
929
+ end
930
+ end
931
+ end
932
+ end
933
+ end
934
+ end
935
+ end
936
+
937
+ context "when trying a nonexistant storage type" do
938
+ setup do
939
+ rebuild_model :storage => :not_here
940
+ end
941
+
942
+ should "not be able to find the module" do
943
+ assert_raise(Paperclip::StorageMethodNotFound){ Dummy.new.avatar }
944
+ end
945
+ end
946
+ end
947
+
948
+ context "An attachment with only a avatar_file_name column" do
949
+ setup do
950
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
951
+ table.column :avatar_file_name, :string
952
+ end
953
+ rebuild_class
954
+ @dummy = Dummy.new
955
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
956
+ end
957
+
958
+ teardown { @file.close }
959
+
960
+ should "not error when assigned an attachment" do
961
+ assert_nothing_raised { @dummy.avatar = @file }
962
+ end
963
+
964
+ should "return the time when sent #avatar_updated_at" do
965
+ now = Time.now
966
+ Time.stubs(:now).returns(now)
967
+ @dummy.avatar = @file
968
+ assert_equal now.to_i, @dummy.avatar.updated_at.to_i
969
+ end
970
+
971
+ should "return nil when reloaded and sent #avatar_updated_at" do
972
+ @dummy.save
973
+ @dummy.reload
974
+ assert_nil @dummy.avatar.updated_at
975
+ end
976
+
977
+ should "return the right value when sent #avatar_file_size" do
978
+ @dummy.avatar = @file
979
+ assert_equal @file.size, @dummy.avatar.size
980
+ end
981
+
982
+ context "and avatar_updated_at column" do
983
+ setup do
984
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_updated_at, :timestamp
985
+ rebuild_class
986
+ @dummy = Dummy.new
987
+ end
988
+
989
+ should "not error when assigned an attachment" do
990
+ assert_nothing_raised { @dummy.avatar = @file }
991
+ end
992
+
993
+ should "return the right value when sent #avatar_updated_at" do
994
+ now = Time.now
995
+ Time.stubs(:now).returns(now)
996
+ @dummy.avatar = @file
997
+ assert_equal now.to_i, @dummy.avatar.updated_at
998
+ end
999
+ end
1000
+
1001
+ context "and avatar_content_type column" do
1002
+ setup do
1003
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string
1004
+ rebuild_class
1005
+ @dummy = Dummy.new
1006
+ end
1007
+
1008
+ should "not error when assigned an attachment" do
1009
+ assert_nothing_raised { @dummy.avatar = @file }
1010
+ end
1011
+
1012
+ should "return the right value when sent #avatar_content_type" do
1013
+ @dummy.avatar = @file
1014
+ assert_equal "image/png", @dummy.avatar.content_type
1015
+ end
1016
+ end
1017
+
1018
+ context "and avatar_file_size column" do
1019
+ setup do
1020
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer
1021
+ rebuild_class
1022
+ @dummy = Dummy.new
1023
+ end
1024
+
1025
+ should "not error when assigned an attachment" do
1026
+ assert_nothing_raised { @dummy.avatar = @file }
1027
+ end
1028
+
1029
+ should "return the right value when sent #avatar_file_size" do
1030
+ @dummy.avatar = @file
1031
+ assert_equal @file.size, @dummy.avatar.size
1032
+ end
1033
+
1034
+ should "return the right value when saved, reloaded, and sent #avatar_file_size" do
1035
+ @dummy.avatar = @file
1036
+ @dummy.save
1037
+ @dummy = Dummy.find(@dummy.id)
1038
+ assert_equal @file.size, @dummy.avatar.size
1039
+ end
1040
+ end
1041
+
1042
+ context "and avatar_fingerprint column" do
1043
+ setup do
1044
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_fingerprint, :string
1045
+ rebuild_class
1046
+ @dummy = Dummy.new
1047
+ end
1048
+
1049
+ should "not error when assigned an attachment" do
1050
+ assert_nothing_raised { @dummy.avatar = @file }
1051
+ end
1052
+
1053
+ should "return the right value when sent #avatar_fingerprint" do
1054
+ @dummy.avatar = @file
1055
+ assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
1056
+ end
1057
+
1058
+ should "return the right value when saved, reloaded, and sent #avatar_fingerprint" do
1059
+ @dummy.avatar = @file
1060
+ @dummy.save
1061
+ @dummy = Dummy.find(@dummy.id)
1062
+ assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
1063
+ end
1064
+ end
1065
+ end
1066
+
1067
+ context "an attachment with delete_file option set to false" do
1068
+ setup do
1069
+ rebuild_model :preserve_files => true
1070
+ @dummy = Dummy.new
1071
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
1072
+ @dummy.avatar = @file
1073
+ @dummy.save!
1074
+ @attachment = @dummy.avatar
1075
+ @path = @attachment.path
1076
+ end
1077
+
1078
+ should "not delete the files from storage when attachment is destroyed" do
1079
+ @attachment.destroy
1080
+ assert File.exists?(@path)
1081
+ end
1082
+
1083
+ should "not delete the file when model is destroyed" do
1084
+ @dummy.destroy
1085
+ assert File.exists?(@path)
1086
+ end
1087
+ end
1088
+
1089
+ context "An attached file" do
1090
+ setup do
1091
+ rebuild_model
1092
+ @dummy = Dummy.new
1093
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
1094
+ @dummy.avatar = @file
1095
+ @dummy.save!
1096
+ @attachment = @dummy.avatar
1097
+ @path = @attachment.path
1098
+ end
1099
+
1100
+ should "not be deleted when the model fails to destroy" do
1101
+ @dummy.stubs(:destroy).raises(Exception)
1102
+
1103
+ assert_raise Exception do
1104
+ @dummy.destroy
1105
+ end
1106
+
1107
+ assert File.exists?(@path), "#{@path} does not exist."
1108
+ end
1109
+
1110
+ should "be deleted when the model is destroyed" do
1111
+ @dummy.destroy
1112
+ assert ! File.exists?(@path), "#{@path} does not exist."
1113
+ end
1114
+ end
1115
+
1116
+ end