mender_paperclip 2.4.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 (70) hide show
  1. data/LICENSE +26 -0
  2. data/README.md +402 -0
  3. data/Rakefile +86 -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 +4 -0
  8. data/lib/generators/paperclip/USAGE +8 -0
  9. data/lib/generators/paperclip/paperclip_generator.rb +33 -0
  10. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  11. data/lib/paperclip/attachment.rb +454 -0
  12. data/lib/paperclip/callback_compatibility.rb +61 -0
  13. data/lib/paperclip/geometry.rb +120 -0
  14. data/lib/paperclip/interpolations.rb +181 -0
  15. data/lib/paperclip/iostream.rb +45 -0
  16. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  17. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
  18. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  19. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  20. data/lib/paperclip/matchers.rb +33 -0
  21. data/lib/paperclip/missing_attachment_styles.rb +87 -0
  22. data/lib/paperclip/options.rb +79 -0
  23. data/lib/paperclip/processor.rb +58 -0
  24. data/lib/paperclip/railtie.rb +26 -0
  25. data/lib/paperclip/storage/filesystem.rb +81 -0
  26. data/lib/paperclip/storage/fog.rb +162 -0
  27. data/lib/paperclip/storage/s3.rb +262 -0
  28. data/lib/paperclip/storage.rb +3 -0
  29. data/lib/paperclip/style.rb +95 -0
  30. data/lib/paperclip/thumbnail.rb +105 -0
  31. data/lib/paperclip/upfile.rb +62 -0
  32. data/lib/paperclip/version.rb +3 -0
  33. data/lib/paperclip.rb +478 -0
  34. data/lib/tasks/paperclip.rake +97 -0
  35. data/rails/init.rb +2 -0
  36. data/shoulda_macros/paperclip.rb +124 -0
  37. data/test/attachment_test.rb +1120 -0
  38. data/test/database.yml +4 -0
  39. data/test/fixtures/12k.png +0 -0
  40. data/test/fixtures/50x50.png +0 -0
  41. data/test/fixtures/5k.png +0 -0
  42. data/test/fixtures/animated.gif +0 -0
  43. data/test/fixtures/bad.png +1 -0
  44. data/test/fixtures/fog.yml +8 -0
  45. data/test/fixtures/s3.yml +8 -0
  46. data/test/fixtures/spaced file.png +0 -0
  47. data/test/fixtures/text.txt +1 -0
  48. data/test/fixtures/twopage.pdf +0 -0
  49. data/test/fixtures/uppercase.PNG +0 -0
  50. data/test/fog_test.rb +191 -0
  51. data/test/geometry_test.rb +206 -0
  52. data/test/helper.rb +152 -0
  53. data/test/integration_test.rb +654 -0
  54. data/test/interpolations_test.rb +195 -0
  55. data/test/iostream_test.rb +71 -0
  56. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  57. data/test/matchers/validate_attachment_content_type_matcher_test.rb +87 -0
  58. data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
  59. data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
  60. data/test/options_test.rb +68 -0
  61. data/test/paperclip_missing_attachment_styles_test.rb +80 -0
  62. data/test/paperclip_test.rb +329 -0
  63. data/test/processor_test.rb +10 -0
  64. data/test/storage/filesystem_test.rb +52 -0
  65. data/test/storage/s3_live_test.rb +51 -0
  66. data/test/storage/s3_test.rb +633 -0
  67. data/test/style_test.rb +180 -0
  68. data/test/thumbnail_test.rb +383 -0
  69. data/test/upfile_test.rb +53 -0
  70. metadata +243 -0
@@ -0,0 +1,654 @@
1
+ require './test/helper'
2
+
3
+ class IntegrationTest < Test::Unit::TestCase
4
+ context "Many models at once" do
5
+ setup do
6
+ rebuild_model
7
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
8
+ 300.times do |i|
9
+ Dummy.create! :avatar => @file
10
+ end
11
+ end
12
+
13
+ should "not exceed the open file limit" do
14
+ assert_nothing_raised do
15
+ dummies = Dummy.find(:all)
16
+ dummies.each { |dummy| dummy.avatar }
17
+ end
18
+ end
19
+ end
20
+
21
+ context "An attachment" do
22
+ setup do
23
+ rebuild_model :styles => { :thumb => "50x50#" }
24
+ @dummy = Dummy.new
25
+ @file = File.new(File.join(File.dirname(__FILE__),
26
+ "fixtures",
27
+ "5k.png"), 'rb')
28
+ @dummy.avatar = @file
29
+ assert @dummy.save
30
+ end
31
+
32
+ teardown { @file.close }
33
+
34
+ should "create its thumbnails properly" do
35
+ assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
36
+ end
37
+
38
+ context 'reprocessing with unreadable original' do
39
+ setup { File.chmod(0000, @dummy.avatar.path) }
40
+
41
+ should "not raise an error" do
42
+ assert_nothing_raised do
43
+ @dummy.avatar.reprocess!
44
+ end
45
+ end
46
+
47
+ should "return false" do
48
+ assert ! @dummy.avatar.reprocess!
49
+ end
50
+
51
+ teardown { File.chmod(0644, @dummy.avatar.path) }
52
+ end
53
+
54
+ context "redefining its attachment styles" do
55
+ setup do
56
+ Dummy.class_eval do
57
+ has_attached_file :avatar, :styles => { :thumb => "150x25#" }
58
+ has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } }
59
+ end
60
+ @d2 = Dummy.find(@dummy.id)
61
+ @original_timestamp = @d2.avatar_updated_at
62
+ @d2.avatar.reprocess!
63
+ @d2.save
64
+ end
65
+
66
+ should "create its thumbnails properly" do
67
+ assert_match /\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
68
+ assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"`
69
+ end
70
+
71
+ should "change the timestamp" do
72
+ assert_not_equal @original_timestamp, @d2.avatar_updated_at
73
+ end
74
+
75
+ should "clean up the old original if it is a tempfile" do
76
+ original = @d2.avatar.to_file(:original)
77
+ tf = Paperclip::Tempfile.new('original')
78
+ tf.binmode
79
+ original.binmode
80
+ tf.write(original.read)
81
+ original.close
82
+ tf.rewind
83
+
84
+ File.expects(:unlink).with(tf.instance_variable_get(:@tmpname))
85
+
86
+ @d2.avatar.expects(:to_file).with(:original).returns(tf)
87
+
88
+ @d2.avatar.reprocess!
89
+ end
90
+ end
91
+ end
92
+
93
+ context "Attachment" do
94
+ setup do
95
+ @thumb_path = "./test/../public/system/avatars/1/thumb/5k.png"
96
+ File.delete(@thumb_path) if File.exists?(@thumb_path)
97
+ rebuild_model :styles => { :thumb => "50x50#" }
98
+ @dummy = Dummy.new
99
+ @file = File.new(File.join(File.dirname(__FILE__),
100
+ "fixtures",
101
+ "5k.png"), 'rb')
102
+
103
+ end
104
+
105
+ teardown { @file.close }
106
+
107
+ should "not create the thumbnails upon saving when post-processing is disabled" do
108
+ @dummy.avatar.post_processing = false
109
+ @dummy.avatar = @file
110
+ assert @dummy.save
111
+ assert !File.exists?(@thumb_path)
112
+ end
113
+
114
+ should "create the thumbnails upon saving when post_processing is enabled" do
115
+ @dummy.avatar.post_processing = true
116
+ @dummy.avatar = @file
117
+ assert @dummy.save
118
+ assert File.exists?(@thumb_path)
119
+ end
120
+ end
121
+
122
+ context "Attachment with no generated thumbnails" do
123
+ setup do
124
+ @thumb_small_path = "./test/../public/system/avatars/1/thumb_small/5k.png"
125
+ @thumb_large_path = "./test/../public/system/avatars/1/thumb_large/5k.png"
126
+ File.delete(@thumb_small_path) if File.exists?(@thumb_small_path)
127
+ File.delete(@thumb_large_path) if File.exists?(@thumb_large_path)
128
+ rebuild_model :styles => { :thumb_small => "50x50#", :thumb_large => "60x60#" }
129
+ @dummy = Dummy.new
130
+ @file = File.new(File.join(File.dirname(__FILE__),
131
+ "fixtures",
132
+ "5k.png"), 'rb')
133
+
134
+ @dummy.avatar.post_processing = false
135
+ @dummy.avatar = @file
136
+ assert @dummy.save
137
+ @dummy.avatar.post_processing = true
138
+ end
139
+
140
+ teardown { @file.close }
141
+
142
+ should "allow us to create all thumbnails in one go" do
143
+ assert !File.exists?(@thumb_small_path)
144
+ assert !File.exists?(@thumb_large_path)
145
+
146
+ @dummy.avatar.reprocess!
147
+
148
+ assert File.exists?(@thumb_small_path)
149
+ assert File.exists?(@thumb_large_path)
150
+ end
151
+
152
+ should "allow us to selectively create each thumbnail" do
153
+ assert !File.exists?(@thumb_small_path)
154
+ assert !File.exists?(@thumb_large_path)
155
+
156
+ @dummy.avatar.reprocess! :thumb_small
157
+ assert File.exists?(@thumb_small_path)
158
+ assert !File.exists?(@thumb_large_path)
159
+
160
+ @dummy.avatar.reprocess! :thumb_large
161
+ assert File.exists?(@thumb_large_path)
162
+ end
163
+ end
164
+
165
+ context "A model that modifies its original" do
166
+ setup do
167
+ rebuild_model :styles => { :original => "2x2#" }
168
+ @dummy = Dummy.new
169
+ @file = File.new(File.join(File.dirname(__FILE__),
170
+ "fixtures",
171
+ "5k.png"), 'rb')
172
+ @dummy.avatar = @file
173
+ end
174
+
175
+ should "report the file size of the processed file and not the original" do
176
+ assert_not_equal @file.size, @dummy.avatar.size
177
+ end
178
+
179
+ teardown { @file.close }
180
+ end
181
+
182
+ context "A model with attachments scoped under an id" do
183
+ setup do
184
+ rebuild_model :styles => { :large => "100x100",
185
+ :medium => "50x50" },
186
+ :path => ":rails_root/tmp/:id/:attachments/:style.:extension"
187
+ @dummy = Dummy.new
188
+ @file = File.new(File.join(File.dirname(__FILE__),
189
+ "fixtures",
190
+ "5k.png"), 'rb')
191
+ @dummy.avatar = @file
192
+ end
193
+
194
+ teardown { @file.close }
195
+
196
+ context "when saved" do
197
+ setup do
198
+ @dummy.save
199
+ @saved_path = @dummy.avatar.path(:large)
200
+ end
201
+
202
+ should "have a large file in the right place" do
203
+ assert File.exists?(@dummy.avatar.path(:large))
204
+ end
205
+
206
+ context "and deleted" do
207
+ setup do
208
+ @dummy.avatar.clear
209
+ @dummy.save
210
+ end
211
+
212
+ should "not have a large file in the right place anymore" do
213
+ assert ! File.exists?(@saved_path)
214
+ end
215
+
216
+ should "not have its next two parent directories" do
217
+ assert ! File.exists?(File.dirname(@saved_path))
218
+ assert ! File.exists?(File.dirname(File.dirname(@saved_path)))
219
+ end
220
+
221
+ before_should "not die if an unexpected SystemCallError happens" do
222
+ FileUtils.stubs(:rmdir).raises(Errno::EPIPE)
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+ context "A model with no attachment validation" do
229
+ setup do
230
+ rebuild_model :styles => { :large => "300x300>",
231
+ :medium => "100x100",
232
+ :thumb => ["32x32#", :gif] },
233
+ :default_style => :medium,
234
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
235
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
236
+ @dummy = Dummy.new
237
+ end
238
+
239
+ should "have its definition return false when asked about whiny_thumbnails" do
240
+ assert ! Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
241
+ end
242
+
243
+ context "when validates_attachment_thumbnails is called" do
244
+ setup do
245
+ Dummy.validates_attachment_thumbnails :avatar
246
+ end
247
+
248
+ should "have its definition return true when asked about whiny_thumbnails" do
249
+ assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
250
+ end
251
+ end
252
+
253
+ context "redefined to have attachment validations" do
254
+ setup do
255
+ rebuild_model :styles => { :large => "300x300>",
256
+ :medium => "100x100",
257
+ :thumb => ["32x32#", :gif] },
258
+ :whiny_thumbnails => true,
259
+ :default_style => :medium,
260
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
261
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
262
+ end
263
+
264
+ should "have its definition return true when asked about whiny_thumbnails" do
265
+ assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
266
+ end
267
+ end
268
+ end
269
+
270
+ context "A model with no convert_options setting" do
271
+ setup do
272
+ rebuild_model :styles => { :large => "300x300>",
273
+ :medium => "100x100",
274
+ :thumb => ["32x32#", :gif] },
275
+ :default_style => :medium,
276
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
277
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
278
+ @dummy = Dummy.new
279
+ end
280
+
281
+ should "have its definition return nil when asked about convert_options" do
282
+ assert ! Dummy.attachment_definitions[:avatar][:convert_options]
283
+ end
284
+
285
+ context "redefined to have convert_options setting" do
286
+ setup do
287
+ rebuild_model :styles => { :large => "300x300>",
288
+ :medium => "100x100",
289
+ :thumb => ["32x32#", :gif] },
290
+ :convert_options => "-strip -depth 8",
291
+ :default_style => :medium,
292
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
293
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
294
+ end
295
+
296
+ should "have its definition return convert_options value when asked about convert_options" do
297
+ assert_equal "-strip -depth 8", Dummy.attachment_definitions[:avatar][:convert_options]
298
+ end
299
+ end
300
+ end
301
+
302
+ context "A model with no source_file_options setting" do
303
+ setup do
304
+ rebuild_model :styles => { :large => "300x300>",
305
+ :medium => "100x100",
306
+ :thumb => ["32x32#", :gif] },
307
+ :default_style => :medium,
308
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
309
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
310
+ @dummy = Dummy.new
311
+ end
312
+
313
+ should "have its definition return nil when asked about source_file_options" do
314
+ assert ! Dummy.attachment_definitions[:avatar][:source_file_options]
315
+ end
316
+
317
+ context "redefined to have source_file_options setting" do
318
+ setup do
319
+ rebuild_model :styles => { :large => "300x300>",
320
+ :medium => "100x100",
321
+ :thumb => ["32x32#", :gif] },
322
+ :source_file_options => "-density 400",
323
+ :default_style => :medium,
324
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
325
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
326
+ end
327
+
328
+ should "have its definition return source_file_options value when asked about source_file_options" do
329
+ assert_equal "-density 400", Dummy.attachment_definitions[:avatar][:source_file_options]
330
+ end
331
+ end
332
+ end
333
+
334
+ context "A model with a filesystem attachment" do
335
+ setup do
336
+ rebuild_model :styles => { :large => "300x300>",
337
+ :medium => "100x100",
338
+ :thumb => ["32x32#", :gif] },
339
+ :whiny_thumbnails => true,
340
+ :default_style => :medium,
341
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
342
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
343
+ @dummy = Dummy.new
344
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
345
+ @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb')
346
+
347
+ assert @dummy.avatar = @file
348
+ assert @dummy.valid?, @dummy.errors.full_messages.join(", ")
349
+ assert @dummy.save
350
+ end
351
+
352
+ should "write and delete its files" do
353
+ [["434x66", :original],
354
+ ["300x46", :large],
355
+ ["100x15", :medium],
356
+ ["32x32", :thumb]].each do |geo, style|
357
+ cmd = %Q[identify -format "%wx%h" "#{@dummy.avatar.path(style)}"]
358
+ assert_equal geo, `#{cmd}`.chomp, cmd
359
+ end
360
+
361
+ saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) }
362
+
363
+ @d2 = Dummy.find(@dummy.id)
364
+ assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path}"`.chomp
365
+ assert_equal "434x66", `identify -format "%wx%h" "#{@d2.avatar.path(:original)}"`.chomp
366
+ assert_equal "300x46", `identify -format "%wx%h" "#{@d2.avatar.path(:large)}"`.chomp
367
+ assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp
368
+ assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp
369
+
370
+ @dummy.avatar = "not a valid file but not nil"
371
+ assert_equal File.basename(@file.path), @dummy.avatar_file_name
372
+ assert @dummy.valid?
373
+ assert @dummy.save
374
+
375
+ saved_paths.each do |p|
376
+ assert File.exists?(p)
377
+ end
378
+
379
+ @dummy.avatar.clear
380
+ assert_nil @dummy.avatar_file_name
381
+ assert @dummy.valid?
382
+ assert @dummy.save
383
+
384
+ saved_paths.each do |p|
385
+ assert ! File.exists?(p)
386
+ end
387
+
388
+ @d2 = Dummy.find(@dummy.id)
389
+ assert_nil @d2.avatar_file_name
390
+ end
391
+
392
+ should "work exactly the same when new as when reloaded" do
393
+ @d2 = Dummy.find(@dummy.id)
394
+
395
+ assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
396
+ [:thumb, :medium, :large, :original].each do |style|
397
+ assert_equal @dummy.avatar.path(style), @d2.avatar.path(style)
398
+ end
399
+
400
+ saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) }
401
+
402
+ @d2.avatar.clear
403
+ assert @d2.save
404
+
405
+ saved_paths.each do |p|
406
+ assert ! File.exists?(p)
407
+ end
408
+ end
409
+
410
+ should "know the difference between good files, bad files, and not files" do
411
+ expected = @dummy.avatar.to_file
412
+ @dummy.avatar = "not a file"
413
+ assert @dummy.valid?
414
+ assert_equal expected.path, @dummy.avatar.path
415
+ expected.close
416
+
417
+ @dummy.avatar = @bad_file
418
+ assert ! @dummy.valid?
419
+ end
420
+
421
+ should "know the difference between good files, bad files, and not files when validating" do
422
+ Dummy.validates_attachment_presence :avatar
423
+ @d2 = Dummy.find(@dummy.id)
424
+ @d2.avatar = @file
425
+ assert @d2.valid?, @d2.errors.full_messages.inspect
426
+ @d2.avatar = @bad_file
427
+ assert ! @d2.valid?
428
+ end
429
+
430
+ should "be able to reload without saving and not have the file disappear" do
431
+ @dummy.avatar = @file
432
+ assert @dummy.save
433
+ @dummy.avatar.clear
434
+ assert_nil @dummy.avatar_file_name
435
+ @dummy.reload
436
+ assert_equal "5k.png", @dummy.avatar_file_name
437
+ end
438
+
439
+ [000,002,022].each do |umask|
440
+ context "when the umask is #{umask}" do
441
+ setup do
442
+ @umask = File.umask umask
443
+ end
444
+
445
+ teardown do
446
+ File.umask @umask
447
+ end
448
+
449
+ should "respect the current umask" do
450
+ @dummy.avatar = @file
451
+ @dummy.save
452
+ assert_equal 0666&~umask, 0666&File.stat(@dummy.avatar.path).mode
453
+ end
454
+ end
455
+ end
456
+
457
+ context "that is assigned its file from another Paperclip attachment" do
458
+ setup do
459
+ @dummy2 = Dummy.new
460
+ @file2 = File.new(File.join(FIXTURES_DIR, "12k.png"), 'rb')
461
+ assert @dummy2.avatar = @file2
462
+ @dummy2.save
463
+ end
464
+
465
+ should "work when assigned a file" do
466
+ assert_not_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
467
+ `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
468
+
469
+ assert @dummy.avatar = @dummy2.avatar
470
+ @dummy.save
471
+ assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
472
+ `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
473
+ assert_equal @dummy.avatar_file_name, @dummy2.avatar_file_name
474
+ end
475
+ end
476
+
477
+ end
478
+
479
+ context "A model with an attachments association and a Paperclip attachment" do
480
+ setup do
481
+ Dummy.class_eval do
482
+ has_many :attachments, :class_name => 'Dummy'
483
+ end
484
+
485
+ @dummy = Dummy.new
486
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__),
487
+ "fixtures",
488
+ "5k.png"), 'rb')
489
+ end
490
+
491
+ should "should not error when saving" do
492
+ assert_nothing_raised do
493
+ @dummy.save!
494
+ end
495
+ end
496
+ end
497
+
498
+ if ENV['S3_TEST_BUCKET']
499
+ def s3_files_for attachment
500
+ [:thumb, :medium, :large, :original].inject({}) do |files, style|
501
+ data = `curl "#{attachment.url(style)}" 2>/dev/null`.chomp
502
+ t = Tempfile.new("paperclip-test")
503
+ t.binmode
504
+ t.write(data)
505
+ t.rewind
506
+ files[style] = t
507
+ files
508
+ end
509
+ end
510
+
511
+ def s3_headers_for attachment, style
512
+ `curl --head "#{attachment.url(style)}" 2>/dev/null`.split("\n").inject({}) do |h,head|
513
+ split_head = head.chomp.split(/\s*:\s*/, 2)
514
+ h[split_head.first.downcase] = split_head.last unless split_head.empty?
515
+ h
516
+ end
517
+ end
518
+
519
+ context "A model with an S3 attachment" do
520
+ setup do
521
+ rebuild_model :styles => { :large => "300x300>",
522
+ :medium => "100x100",
523
+ :thumb => ["32x32#", :gif] },
524
+ :storage => :s3,
525
+ :whiny_thumbnails => true,
526
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")),
527
+ :default_style => :medium,
528
+ :bucket => ENV['S3_TEST_BUCKET'],
529
+ :path => ":class/:attachment/:id/:style/:basename.:extension"
530
+ @dummy = Dummy.new
531
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
532
+ @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb')
533
+
534
+ assert @dummy.avatar = @file
535
+ assert @dummy.valid?
536
+ assert @dummy.save
537
+
538
+ @files_on_s3 = s3_files_for @dummy.avatar
539
+ end
540
+
541
+ context 'assigning itself to a new model' do
542
+ setup do
543
+ @d2 = Dummy.new
544
+ @d2.avatar = @dummy.avatar
545
+ @d2.save
546
+ end
547
+
548
+ should "have the same name as the old file" do
549
+ assert_equal @d2.avatar.original_filename, @dummy.avatar.original_filename
550
+ end
551
+ end
552
+
553
+ should "have the same contents as the original" do
554
+ @file.rewind
555
+ assert_equal @file.read, @files_on_s3[:original].read
556
+ end
557
+
558
+ should "write and delete its files" do
559
+ [["434x66", :original],
560
+ ["300x46", :large],
561
+ ["100x15", :medium],
562
+ ["32x32", :thumb]].each do |geo, style|
563
+ cmd = %Q[identify -format "%wx%h" "#{@files_on_s3[style].path}"]
564
+ assert_equal geo, `#{cmd}`.chomp, cmd
565
+ end
566
+
567
+ @d2 = Dummy.find(@dummy.id)
568
+ @d2_files = s3_files_for @d2.avatar
569
+ [["434x66", :original],
570
+ ["300x46", :large],
571
+ ["100x15", :medium],
572
+ ["32x32", :thumb]].each do |geo, style|
573
+ cmd = %Q[identify -format "%wx%h" "#{@d2_files[style].path}"]
574
+ assert_equal geo, `#{cmd}`.chomp, cmd
575
+ end
576
+
577
+ @dummy.avatar = "not a valid file but not nil"
578
+ assert_equal File.basename(@file.path), @dummy.avatar_file_name
579
+ assert @dummy.valid?
580
+ assert @dummy.save
581
+
582
+ [:thumb, :medium, :large, :original].each do |style|
583
+ assert @dummy.avatar.exists?(style)
584
+ end
585
+
586
+ @dummy.avatar.clear
587
+ assert_nil @dummy.avatar_file_name
588
+ assert @dummy.valid?
589
+ assert @dummy.save
590
+
591
+ [:thumb, :medium, :large, :original].each do |style|
592
+ assert ! @dummy.avatar.exists?(style)
593
+ end
594
+
595
+ @d2 = Dummy.find(@dummy.id)
596
+ assert_nil @d2.avatar_file_name
597
+ end
598
+
599
+ should "work exactly the same when new as when reloaded" do
600
+ @d2 = Dummy.find(@dummy.id)
601
+
602
+ assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
603
+ [:thumb, :medium, :large, :original].each do |style|
604
+ assert_equal @dummy.avatar.to_file(style).read, @d2.avatar.to_file(style).read
605
+ end
606
+
607
+ saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) }
608
+
609
+ @d2.avatar.clear
610
+ assert @d2.save
611
+
612
+ [:thumb, :medium, :large, :original].each do |style|
613
+ assert ! @dummy.avatar.exists?(style)
614
+ end
615
+ end
616
+
617
+ should "know the difference between good files, bad files, not files, and nil" do
618
+ expected = @dummy.avatar.to_file
619
+ @dummy.avatar = "not a file"
620
+ assert @dummy.valid?
621
+ assert_equal expected.read, @dummy.avatar.to_file.read
622
+
623
+ @dummy.avatar = @bad_file
624
+ assert ! @dummy.valid?
625
+ @dummy.avatar = nil
626
+ assert @dummy.valid?
627
+
628
+ Dummy.validates_attachment_presence :avatar
629
+ @d2 = Dummy.find(@dummy.id)
630
+ @d2.avatar = @file
631
+ assert @d2.valid?
632
+ @d2.avatar = @bad_file
633
+ assert ! @d2.valid?
634
+ @d2.avatar = nil
635
+ assert ! @d2.valid?
636
+ end
637
+
638
+ should "be able to reload without saving and not have the file disappear" do
639
+ @dummy.avatar = @file
640
+ assert @dummy.save
641
+ @dummy.avatar = nil
642
+ assert_nil @dummy.avatar_file_name
643
+ @dummy.reload
644
+ assert_equal "5k.png", @dummy.avatar_file_name
645
+ end
646
+
647
+ should "have the right content type" do
648
+ headers = s3_headers_for(@dummy.avatar, :original)
649
+ assert_equal 'image/png', headers['content-type']
650
+ end
651
+ end
652
+ end
653
+ end
654
+