lostboy-paperclip 2.2.6.1

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