cemeng-paperclip 2.3.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 (62) hide show
  1. data/LICENSE +26 -0
  2. data/README.rdoc +182 -0
  3. data/Rakefile +80 -0
  4. data/generators/paperclip/USAGE +5 -0
  5. data/generators/paperclip/paperclip_generator.rb +27 -0
  6. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  7. data/init.rb +1 -0
  8. data/lib/generators/paperclip/USAGE +8 -0
  9. data/lib/generators/paperclip/paperclip_generator.rb +31 -0
  10. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  11. data/lib/paperclip.rb +402 -0
  12. data/lib/paperclip/attachment.rb +347 -0
  13. data/lib/paperclip/callback_compatability.rb +61 -0
  14. data/lib/paperclip/command_line.rb +80 -0
  15. data/lib/paperclip/geometry.rb +115 -0
  16. data/lib/paperclip/interpolations.rb +114 -0
  17. data/lib/paperclip/iostream.rb +45 -0
  18. data/lib/paperclip/matchers.rb +33 -0
  19. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  20. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +75 -0
  21. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  22. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  23. data/lib/paperclip/processor.rb +58 -0
  24. data/lib/paperclip/railtie.rb +25 -0
  25. data/lib/paperclip/storage.rb +3 -0
  26. data/lib/paperclip/storage/database.rb +204 -0
  27. data/lib/paperclip/storage/filesystem.rb +73 -0
  28. data/lib/paperclip/storage/s3.rb +192 -0
  29. data/lib/paperclip/style.rb +91 -0
  30. data/lib/paperclip/thumbnail.rb +79 -0
  31. data/lib/paperclip/upfile.rb +55 -0
  32. data/lib/paperclip/version.rb +3 -0
  33. data/lib/tasks/paperclip.rake +79 -0
  34. data/rails/init.rb +2 -0
  35. data/shoulda_macros/paperclip.rb +118 -0
  36. data/test/attachment_test.rb +804 -0
  37. data/test/command_line_test.rb +133 -0
  38. data/test/database.yml +4 -0
  39. data/test/database_storage_test.rb +267 -0
  40. data/test/fixtures/12k.png +0 -0
  41. data/test/fixtures/50x50.png +0 -0
  42. data/test/fixtures/5k.png +0 -0
  43. data/test/fixtures/bad.png +1 -0
  44. data/test/fixtures/s3.yml +8 -0
  45. data/test/fixtures/text.txt +0 -0
  46. data/test/fixtures/twopage.pdf +0 -0
  47. data/test/geometry_test.rb +177 -0
  48. data/test/helper.rb +146 -0
  49. data/test/integration_test.rb +482 -0
  50. data/test/interpolations_test.rb +127 -0
  51. data/test/iostream_test.rb +71 -0
  52. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  53. data/test/matchers/validate_attachment_content_type_matcher_test.rb +47 -0
  54. data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
  55. data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
  56. data/test/paperclip_test.rb +254 -0
  57. data/test/processor_test.rb +10 -0
  58. data/test/storage_test.rb +363 -0
  59. data/test/style_test.rb +141 -0
  60. data/test/thumbnail_test.rb +227 -0
  61. data/test/upfile_test.rb +36 -0
  62. metadata +186 -0
@@ -0,0 +1,2 @@
1
+ require 'paperclip/railtie'
2
+ Paperclip::Railtie.insert
@@ -0,0 +1,118 @@
1
+ require 'paperclip/matchers'
2
+
3
+ module Paperclip
4
+ # =Paperclip Shoulda Macros
5
+ #
6
+ # These macros are intended for use with shoulda, and will be included into
7
+ # your tests automatically. All of the macros use the standard shoulda
8
+ # assumption that the name of the test is based on the name of the model
9
+ # you're testing (that is, UserTest is the test for the User model), and
10
+ # will load that class for testing purposes.
11
+ module Shoulda
12
+ include Matchers
13
+ # This will test whether you have defined your attachment correctly by
14
+ # checking for all the required fields exist after the definition of the
15
+ # attachment.
16
+ def should_have_attached_file name
17
+ klass = self.name.gsub(/Test$/, '').constantize
18
+ matcher = have_attached_file name
19
+ should matcher.description do
20
+ assert_accepts(matcher, klass)
21
+ end
22
+ end
23
+
24
+ # Tests for validations on the presence of the attachment.
25
+ def should_validate_attachment_presence name
26
+ klass = self.name.gsub(/Test$/, '').constantize
27
+ matcher = validate_attachment_presence name
28
+ should matcher.description do
29
+ assert_accepts(matcher, klass)
30
+ end
31
+ end
32
+
33
+ # Tests that you have content_type validations specified. There are two
34
+ # options, :valid and :invalid. Both accept an array of strings. The
35
+ # strings should be a list of content types which will pass and fail
36
+ # validation, respectively.
37
+ def should_validate_attachment_content_type name, options = {}
38
+ klass = self.name.gsub(/Test$/, '').constantize
39
+ valid = [options[:valid]].flatten
40
+ invalid = [options[:invalid]].flatten
41
+ matcher = validate_attachment_content_type(name).allowing(valid).rejecting(invalid)
42
+ should matcher.description do
43
+ assert_accepts(matcher, klass)
44
+ end
45
+ end
46
+
47
+ # Tests to ensure that you have file size validations turned on. You
48
+ # can pass the same options to this that you can to
49
+ # validate_attachment_file_size - :less_than, :greater_than, and :in.
50
+ # :less_than checks that a file is less than a certain size, :greater_than
51
+ # checks that a file is more than a certain size, and :in takes a Range or
52
+ # Array which specifies the lower and upper limits of the file size.
53
+ def should_validate_attachment_size name, options = {}
54
+ klass = self.name.gsub(/Test$/, '').constantize
55
+ min = options[:greater_than] || (options[:in] && options[:in].first) || 0
56
+ max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
57
+ range = (min..max)
58
+ matcher = validate_attachment_size(name).in(range)
59
+ should matcher.description do
60
+ assert_accepts(matcher, klass)
61
+ end
62
+ end
63
+
64
+ # Stubs the HTTP PUT for an attachment using S3 storage.
65
+ #
66
+ # @example
67
+ # stub_paperclip_s3('user', 'avatar', 'png')
68
+ def stub_paperclip_s3(model, attachment, extension)
69
+ definition = model.gsub(" ", "_").classify.constantize.
70
+ attachment_definitions[attachment.to_sym]
71
+
72
+ path = "http://s3.amazonaws.com/:id/#{definition[:path]}"
73
+ path.gsub!(/:([^\/\.]+)/) do |match|
74
+ "([^\/\.]+)"
75
+ end
76
+
77
+ begin
78
+ FakeWeb.register_uri(:put, Regexp.new(path), :body => "OK")
79
+ rescue NameError
80
+ raise NameError, "the stub_paperclip_s3 shoulda macro requires the fakeweb gem."
81
+ end
82
+ end
83
+
84
+ # Stub S3 and return a file for attachment. Best with Factory Girl.
85
+ # Uses a strict directory convention:
86
+ #
87
+ # features/support/paperclip
88
+ #
89
+ # This method is used by the Paperclip-provided Cucumber step:
90
+ #
91
+ # When I attach a "demo_tape" "mp3" file to a "band" on S3
92
+ #
93
+ # @example
94
+ # Factory.define :band_with_demo_tape, :parent => :band do |band|
95
+ # band.demo_tape { band.paperclip_fixture("band", "demo_tape", "png") }
96
+ # end
97
+ def paperclip_fixture(model, attachment, extension)
98
+ stub_paperclip_s3(model, attachment, extension)
99
+ base_path = File.join(File.dirname(__FILE__), "..", "..",
100
+ "features", "support", "paperclip")
101
+ File.new(File.join(base_path, model, "#{attachment}.#{extension}"))
102
+ end
103
+ end
104
+ end
105
+
106
+ if defined?(ActionController::Integration::Session)
107
+ class ActionController::Integration::Session #:nodoc:
108
+ include Paperclip::Shoulda
109
+ end
110
+ end
111
+
112
+ class Factory
113
+ include Paperclip::Shoulda #:nodoc:
114
+ end
115
+
116
+ class Test::Unit::TestCase #:nodoc:
117
+ extend Paperclip::Shoulda
118
+ end
@@ -0,0 +1,804 @@
1
+ # encoding: utf-8
2
+ require './test/helper'
3
+
4
+ class Dummy
5
+ # This is a dummy class
6
+ end
7
+
8
+ class AttachmentTest < Test::Unit::TestCase
9
+ should "return the path based on the url by default" do
10
+ @attachment = attachment :url => "/:class/:id/:basename"
11
+ @model = @attachment.instance
12
+ @model.id = 1234
13
+ @model.avatar_file_name = "fake.jpg"
14
+ assert_equal "#{Rails.root}/public/fake_models/1234/fake", @attachment.path
15
+ end
16
+
17
+ context "Attachment default_options" do
18
+ setup do
19
+ rebuild_model
20
+ @old_default_options = Paperclip::Attachment.default_options.dup
21
+ @new_default_options = @old_default_options.merge({
22
+ :path => "argle/bargle",
23
+ :url => "fooferon",
24
+ :default_url => "not here.png"
25
+ })
26
+ end
27
+
28
+ teardown do
29
+ Paperclip::Attachment.default_options.merge! @old_default_options
30
+ end
31
+
32
+ should "be overrideable" do
33
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
34
+ @new_default_options.keys.each do |key|
35
+ assert_equal @new_default_options[key],
36
+ Paperclip::Attachment.default_options[key]
37
+ end
38
+ end
39
+
40
+ context "without an Attachment" do
41
+ setup do
42
+ @dummy = Dummy.new
43
+ end
44
+
45
+ should "return false when asked exists?" do
46
+ assert !@dummy.avatar.exists?
47
+ end
48
+ end
49
+
50
+ context "on an Attachment" do
51
+ setup do
52
+ @dummy = Dummy.new
53
+ @attachment = @dummy.avatar
54
+ end
55
+
56
+ Paperclip::Attachment.default_options.keys.each do |key|
57
+ should "be the default_options for #{key}" do
58
+ assert_equal @old_default_options[key],
59
+ @attachment.instance_variable_get("@#{key}"),
60
+ key
61
+ end
62
+ end
63
+
64
+ context "when redefined" do
65
+ setup do
66
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
67
+ @dummy = Dummy.new
68
+ @attachment = @dummy.avatar
69
+ end
70
+
71
+ Paperclip::Attachment.default_options.keys.each do |key|
72
+ should "be the new default_options for #{key}" do
73
+ assert_equal @new_default_options[key],
74
+ @attachment.instance_variable_get("@#{key}"),
75
+ key
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ context "An attachment with similarly named interpolations" do
83
+ setup do
84
+ rebuild_model :path => ":id.omg/:id-bbq/:idwhat/:id_partition.wtf"
85
+ @dummy = Dummy.new
86
+ @dummy.stubs(:id).returns(1024)
87
+ @file = File.new(File.join(File.dirname(__FILE__),
88
+ "fixtures",
89
+ "5k.png"), 'rb')
90
+ @dummy.avatar = @file
91
+ end
92
+
93
+ teardown { @file.close }
94
+
95
+ should "make sure that they are interpolated correctly" do
96
+ assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path
97
+ end
98
+ end
99
+
100
+ context "An attachment with a :rails_env interpolation" do
101
+ setup do
102
+ @rails_env = "blah"
103
+ @id = 1024
104
+ rebuild_model :path => ":rails_env/:id.png"
105
+ @dummy = Dummy.new
106
+ @dummy.stubs(:id).returns(@id)
107
+ @file = StringIO.new(".")
108
+ @dummy.avatar = @file
109
+ Rails.stubs(:env).returns(@rails_env)
110
+ end
111
+
112
+ should "return the proper path" do
113
+ assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path
114
+ end
115
+ end
116
+
117
+ context "An attachment with a default style and an extension interpolation" do
118
+ setup do
119
+ @attachment = attachment :path => ":basename.:extension",
120
+ :styles => { :default => ["100x100", :png] },
121
+ :default_style => :default
122
+ @file = StringIO.new("...")
123
+ @file.stubs(:original_filename).returns("file.jpg")
124
+ end
125
+ should "return the right extension for the path" do
126
+ @attachment.assign(@file)
127
+ assert_equal "file.png", @attachment.path
128
+ end
129
+ end
130
+
131
+ context "An attachment with :convert_options" do
132
+ setup do
133
+ rebuild_model :styles => {
134
+ :thumb => "100x100",
135
+ :large => "400x400"
136
+ },
137
+ :convert_options => {
138
+ :all => "-do_stuff",
139
+ :thumb => "-thumbnailize"
140
+ }
141
+ @dummy = Dummy.new
142
+ @dummy.avatar
143
+ end
144
+
145
+ should "report the correct options when sent #extra_options_for(:thumb)" do
146
+ assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
147
+ end
148
+
149
+ should "report the correct options when sent #extra_options_for(:large)" do
150
+ assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
151
+ end
152
+ end
153
+
154
+ context "An attachment with :convert_options that is a proc" do
155
+ setup do
156
+ rebuild_model :styles => {
157
+ :thumb => "100x100",
158
+ :large => "400x400"
159
+ },
160
+ :convert_options => {
161
+ :all => lambda{|i| i.all },
162
+ :thumb => lambda{|i| i.thumb }
163
+ }
164
+ Dummy.class_eval do
165
+ def all; "-all"; end
166
+ def thumb; "-thumb"; end
167
+ end
168
+ @dummy = Dummy.new
169
+ @dummy.avatar
170
+ end
171
+
172
+ should "report the correct options when sent #extra_options_for(:thumb)" do
173
+ assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
174
+ end
175
+
176
+ should "report the correct options when sent #extra_options_for(:large)" do
177
+ assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
178
+ end
179
+ end
180
+
181
+ context "An attachment with :path that is a proc" do
182
+ setup do
183
+ rebuild_model :path => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
184
+
185
+ @file = File.new(File.join(File.dirname(__FILE__),
186
+ "fixtures",
187
+ "5k.png"), 'rb')
188
+ @dummyA = Dummy.new(:other => 'a')
189
+ @dummyA.avatar = @file
190
+ @dummyB = Dummy.new(:other => 'b')
191
+ @dummyB.avatar = @file
192
+ end
193
+
194
+ teardown { @file.close }
195
+
196
+ should "return correct path" do
197
+ assert_equal "path/a.png", @dummyA.avatar.path
198
+ assert_equal "path/b.png", @dummyB.avatar.path
199
+ end
200
+ end
201
+
202
+ context "An attachment with :styles that is a proc" do
203
+ setup do
204
+ rebuild_model :styles => lambda{ |attachment| {:thumb => "50x50#", :large => "400x400"} }
205
+
206
+ @attachment = Dummy.new.avatar
207
+ end
208
+
209
+ should "have the correct geometry" do
210
+ assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
211
+ end
212
+ end
213
+
214
+ context "An attachment with :url that is a proc" do
215
+ setup do
216
+ rebuild_model :url => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
217
+
218
+ @file = File.new(File.join(File.dirname(__FILE__),
219
+ "fixtures",
220
+ "5k.png"), 'rb')
221
+ @dummyA = Dummy.new(:other => 'a')
222
+ @dummyA.avatar = @file
223
+ @dummyB = Dummy.new(:other => 'b')
224
+ @dummyB.avatar = @file
225
+ end
226
+
227
+ teardown { @file.close }
228
+
229
+ should "return correct url" do
230
+ assert_equal "path/a.png", @dummyA.avatar.url(:original, false)
231
+ assert_equal "path/b.png", @dummyB.avatar.url(:original, false)
232
+ end
233
+ end
234
+
235
+ geometry_specs = [
236
+ [ lambda{|z| "50x50#" }, :png ],
237
+ lambda{|z| "50x50#" },
238
+ { :geometry => lambda{|z| "50x50#" } }
239
+ ]
240
+ geometry_specs.each do |geometry_spec|
241
+ context "An attachment geometry like #{geometry_spec}" do
242
+ setup do
243
+ rebuild_model :styles => { :normal => geometry_spec }
244
+ @attachment = Dummy.new.avatar
245
+ end
246
+
247
+ context "when assigned" do
248
+ setup do
249
+ @file = StringIO.new(".")
250
+ @attachment.assign(@file)
251
+ end
252
+
253
+ should "have the correct geometry" do
254
+ assert_equal "50x50#", @attachment.styles[:normal][:geometry]
255
+ end
256
+ end
257
+ end
258
+ end
259
+
260
+ context "An attachment with both 'normal' and hash-style styles" do
261
+ setup do
262
+ rebuild_model :styles => {
263
+ :normal => ["50x50#", :png],
264
+ :hash => { :geometry => "50x50#", :format => :png }
265
+ }
266
+ @dummy = Dummy.new
267
+ @attachment = @dummy.avatar
268
+ end
269
+
270
+ [:processors, :whiny, :convert_options, :geometry, :format].each do |field|
271
+ should "have the same #{field} field" do
272
+ assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field]
273
+ end
274
+ end
275
+ end
276
+
277
+ context "An attachment with :processors that is a proc" do
278
+ setup do
279
+ rebuild_model :styles => { :normal => '' }, :processors => lambda { |a| [ :test ] }
280
+ @attachment = Dummy.new.avatar
281
+ end
282
+
283
+ context "when assigned" do
284
+ setup do
285
+ @attachment.assign(StringIO.new("."))
286
+ end
287
+
288
+ should "have the correct processors" do
289
+ assert_equal [ :test ], @attachment.styles[:normal][:processors]
290
+ end
291
+ end
292
+ end
293
+
294
+ context "An attachment with erroring processor" do
295
+ setup do
296
+ rebuild_model :processor => [:thumbnail], :styles => { :small => '' }, :whiny_thumbnails => true
297
+ @dummy = Dummy.new
298
+ Paperclip::Thumbnail.expects(:make).raises(Paperclip::PaperclipError, "cannot be processed.")
299
+ @file = StringIO.new("...")
300
+ @file.stubs(:to_tempfile).returns(@file)
301
+ @dummy.avatar = @file
302
+ end
303
+
304
+ should "correctly forward processing error message to the instance" do
305
+ @dummy.valid?
306
+ assert_contains @dummy.errors.full_messages, "Avatar cannot be processed."
307
+ end
308
+ end
309
+
310
+ context "An attachment with multiple processors" do
311
+ setup do
312
+ class Paperclip::Test < Paperclip::Processor; end
313
+ @style_params = { :once => {:one => 1, :two => 2} }
314
+ rebuild_model :processors => [:thumbnail, :test], :styles => @style_params
315
+ @dummy = Dummy.new
316
+ @file = StringIO.new("...")
317
+ @file.stubs(:to_tempfile).returns(@file)
318
+ Paperclip::Test.stubs(:make).returns(@file)
319
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
320
+ end
321
+
322
+ context "when assigned" do
323
+ setup { @dummy.avatar = @file }
324
+
325
+ before_should "call #make on all specified processors" do
326
+ Paperclip::Thumbnail.expects(:make).with(any_parameters).returns(@file)
327
+ Paperclip::Test.expects(:make).with(any_parameters).returns(@file)
328
+ end
329
+
330
+ before_should "call #make with the right parameters passed as second argument" do
331
+ expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""})
332
+ Paperclip::Thumbnail.expects(:make).with(anything, expected_params, anything).returns(@file)
333
+ end
334
+
335
+ before_should "call #make with attachment passed as third argument" do
336
+ Paperclip::Test.expects(:make).with(anything, anything, @dummy.avatar).returns(@file)
337
+ end
338
+ end
339
+ end
340
+
341
+ should "include the filesystem module when loading the filesystem storage" do
342
+ rebuild_model :storage => :filesystem
343
+ @dummy = Dummy.new
344
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
345
+ end
346
+
347
+ should "include the filesystem module even if capitalization is wrong" do
348
+ rebuild_model :storage => :FileSystem
349
+ @dummy = Dummy.new
350
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
351
+ end
352
+
353
+ should "raise an error if you try to include a storage module that doesn't exist" do
354
+ rebuild_model :storage => :not_here
355
+ @dummy = Dummy.new
356
+ assert_raises(Paperclip::StorageMethodNotFound) do
357
+ @dummy.avatar
358
+ end
359
+ end
360
+
361
+ context "An attachment with styles but no processors defined" do
362
+ setup do
363
+ rebuild_model :processors => [], :styles => {:something => '1'}
364
+ @dummy = Dummy.new
365
+ @file = StringIO.new("...")
366
+ end
367
+ should "raise when assigned to" do
368
+ assert_raises(RuntimeError){ @dummy.avatar = @file }
369
+ end
370
+ end
371
+
372
+ context "An attachment without styles and with no processors defined" do
373
+ setup do
374
+ rebuild_model :processors => [], :styles => {}
375
+ @dummy = Dummy.new
376
+ @file = StringIO.new("...")
377
+ end
378
+ should "not raise when assigned to" do
379
+ @dummy.avatar = @file
380
+ end
381
+ end
382
+
383
+ context "Assigning an attachment with post_process hooks" do
384
+ setup do
385
+ rebuild_class :styles => { :something => "100x100#" }
386
+ Dummy.class_eval do
387
+ before_avatar_post_process :do_before_avatar
388
+ after_avatar_post_process :do_after_avatar
389
+ before_post_process :do_before_all
390
+ after_post_process :do_after_all
391
+ def do_before_avatar; end
392
+ def do_after_avatar; end
393
+ def do_before_all; end
394
+ def do_after_all; end
395
+ end
396
+ @file = StringIO.new(".")
397
+ @file.stubs(:to_tempfile).returns(@file)
398
+ @dummy = Dummy.new
399
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
400
+ @attachment = @dummy.avatar
401
+ end
402
+
403
+ should "call the defined callbacks when assigned" do
404
+ @dummy.expects(:do_before_avatar).with()
405
+ @dummy.expects(:do_after_avatar).with()
406
+ @dummy.expects(:do_before_all).with()
407
+ @dummy.expects(:do_after_all).with()
408
+ Paperclip::Thumbnail.expects(:make).returns(@file)
409
+ @dummy.avatar = @file
410
+ end
411
+
412
+ should "not cancel the processing if a before_post_process returns nil" do
413
+ @dummy.expects(:do_before_avatar).with().returns(nil)
414
+ @dummy.expects(:do_after_avatar).with()
415
+ @dummy.expects(:do_before_all).with().returns(nil)
416
+ @dummy.expects(:do_after_all).with()
417
+ Paperclip::Thumbnail.expects(:make).returns(@file)
418
+ @dummy.avatar = @file
419
+ end
420
+
421
+ should "cancel the processing if a before_post_process returns false" do
422
+ @dummy.expects(:do_before_avatar).never
423
+ @dummy.expects(:do_after_avatar).never
424
+ @dummy.expects(:do_before_all).with().returns(false)
425
+ @dummy.expects(:do_after_all)
426
+ Paperclip::Thumbnail.expects(:make).never
427
+ @dummy.avatar = @file
428
+ end
429
+
430
+ should "cancel the processing if a before_avatar_post_process returns false" do
431
+ @dummy.expects(:do_before_avatar).with().returns(false)
432
+ @dummy.expects(:do_after_avatar)
433
+ @dummy.expects(:do_before_all).with().returns(true)
434
+ @dummy.expects(:do_after_all)
435
+ Paperclip::Thumbnail.expects(:make).never
436
+ @dummy.avatar = @file
437
+ end
438
+ end
439
+
440
+ context "Assigning an attachment" do
441
+ setup do
442
+ rebuild_model :styles => { :something => "100x100#" }
443
+ @file = StringIO.new(".")
444
+ @file.stubs(:original_filename).returns("5k.png\n\n")
445
+ @file.stubs(:content_type).returns("image/png\n\n")
446
+ @file.stubs(:to_tempfile).returns(@file)
447
+ @dummy = Dummy.new
448
+ Paperclip::Thumbnail.expects(:make).returns(@file)
449
+ @attachment = @dummy.avatar
450
+ @dummy.avatar = @file
451
+ end
452
+
453
+ should "strip whitespace from original_filename field" do
454
+ assert_equal "5k.png", @dummy.avatar.original_filename
455
+ end
456
+
457
+ should "strip whitespace from content_type field" do
458
+ assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
459
+ end
460
+ end
461
+
462
+ context "Attachment with strange letters" do
463
+ setup do
464
+ rebuild_model
465
+
466
+ @not_file = mock("not_file")
467
+ @tempfile = mock("tempfile")
468
+ @not_file.stubs(:nil?).returns(false)
469
+ @not_file.expects(:size).returns(10)
470
+ @tempfile.expects(:size).returns(10)
471
+ @not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n")
472
+ @not_file.expects(:content_type).returns("image/png\r\n")
473
+
474
+ @dummy = Dummy.new
475
+ @attachment = @dummy.avatar
476
+ @attachment.expects(:valid_assignment?).with(@not_file).returns(true)
477
+ @attachment.expects(:queue_existing_for_delete)
478
+ @attachment.expects(:post_process)
479
+ @attachment.expects(:to_tempfile).returns(@tempfile)
480
+ @attachment.expects(:generate_fingerprint).with(@tempfile).returns("12345")
481
+ @attachment.expects(:generate_fingerprint).with(@not_file).returns("12345")
482
+ @dummy.avatar = @not_file
483
+ end
484
+
485
+ should "not remove strange letters" do
486
+ assert_equal "sheep_say_bæ.png", @dummy.avatar.original_filename
487
+ end
488
+ end
489
+
490
+ context "An attachment" do
491
+ setup do
492
+ @old_defaults = Paperclip::Attachment.default_options.dup
493
+ Paperclip::Attachment.default_options.merge!({
494
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
495
+ })
496
+ FileUtils.rm_rf("tmp")
497
+ rebuild_model
498
+ @instance = Dummy.new
499
+ @instance.stubs(:id).returns 123
500
+ @attachment = Paperclip::Attachment.new(:avatar, @instance)
501
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
502
+ end
503
+
504
+ teardown do
505
+ @file.close
506
+ Paperclip::Attachment.default_options.merge!(@old_defaults)
507
+ end
508
+
509
+ should "raise if there are not the correct columns when you try to assign" do
510
+ @other_attachment = Paperclip::Attachment.new(:not_here, @instance)
511
+ assert_raises(Paperclip::PaperclipError) do
512
+ @other_attachment.assign(@file)
513
+ end
514
+ end
515
+
516
+ should "return its default_url when no file assigned" do
517
+ assert @attachment.to_file.nil?
518
+ assert_equal "/avatars/original/missing.png", @attachment.url
519
+ assert_equal "/avatars/blah/missing.png", @attachment.url(:blah)
520
+ end
521
+
522
+ should "return nil as path when no file assigned" do
523
+ assert @attachment.to_file.nil?
524
+ assert_equal nil, @attachment.path
525
+ assert_equal nil, @attachment.path(:blah)
526
+ end
527
+
528
+ context "with a file assigned in the database" do
529
+ setup do
530
+ @attachment.stubs(:instance_read).with(:file_name).returns("5k.png")
531
+ @attachment.stubs(:instance_read).with(:content_type).returns("image/png")
532
+ @attachment.stubs(:instance_read).with(:file_size).returns(12345)
533
+ dtnow = DateTime.now
534
+ @now = Time.now
535
+ Time.stubs(:now).returns(@now)
536
+ @attachment.stubs(:instance_read).with(:updated_at).returns(dtnow)
537
+ end
538
+
539
+ should "return a correct url even if the file does not exist" do
540
+ assert_nil @attachment.to_file
541
+ assert_match %r{^/system/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
542
+ end
543
+
544
+ should "make sure the updated_at mtime is in the url if it is defined" do
545
+ assert_match %r{#{@now.to_i}$}, @attachment.url(:blah)
546
+ end
547
+
548
+ should "make sure the updated_at mtime is NOT in the url if false is passed to the url method" do
549
+ assert_no_match %r{#{@now.to_i}$}, @attachment.url(:blah, false)
550
+ end
551
+
552
+ context "with the updated_at field removed" do
553
+ setup do
554
+ @attachment.stubs(:instance_read).with(:updated_at).returns(nil)
555
+ end
556
+
557
+ should "only return the url without the updated_at when sent #url" do
558
+ assert_match "/avatars/#{@instance.id}/blah/5k.png", @attachment.url(:blah)
559
+ end
560
+ end
561
+
562
+ should "return the proper path when filename has a single .'s" do
563
+ assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.png"), File.expand_path(@attachment.path)
564
+ end
565
+
566
+ should "return the proper path when filename has multiple .'s" do
567
+ @attachment.stubs(:instance_read).with(:file_name).returns("5k.old.png")
568
+ assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png"), File.expand_path(@attachment.path)
569
+ end
570
+
571
+ context "when expecting three styles" do
572
+ setup do
573
+ styles = {:styles => { :large => ["400x400", :png],
574
+ :medium => ["100x100", :gif],
575
+ :small => ["32x32#", :jpg]}}
576
+ @attachment = Paperclip::Attachment.new(:avatar,
577
+ @instance,
578
+ styles)
579
+ end
580
+
581
+ context "and assigned a file" do
582
+ setup do
583
+ now = Time.now
584
+ Time.stubs(:now).returns(now)
585
+ @attachment.assign(@file)
586
+ end
587
+
588
+ should "be dirty" do
589
+ assert @attachment.dirty?
590
+ end
591
+
592
+ context "and saved" do
593
+ setup do
594
+ @attachment.save
595
+ end
596
+
597
+ should "return the real url" do
598
+ file = @attachment.to_file
599
+ assert file
600
+ assert_match %r{^/system/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
601
+ assert_match %r{^/system/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
602
+ file.close
603
+ end
604
+
605
+ should "commit the files to disk" do
606
+ [:large, :medium, :small].each do |style|
607
+ io = @attachment.to_file(style)
608
+ # p "in commit to disk test, io is #{io.inspect} and @instance.id is #{@instance.id}"
609
+ assert File.exists?(io.path)
610
+ assert ! io.is_a?(::Tempfile)
611
+ io.close
612
+ end
613
+ end
614
+
615
+ should "save the files as the right formats and sizes" do
616
+ [[:large, 400, 61, "PNG"],
617
+ [:medium, 100, 15, "GIF"],
618
+ [:small, 32, 32, "JPEG"]].each do |style|
619
+ cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"]
620
+ out = `#{cmd}`
621
+ width, height, size, format = out.split(" ")
622
+ assert_equal style[1].to_s, width.to_s
623
+ assert_equal style[2].to_s, height.to_s
624
+ assert_equal style[3].to_s, format.to_s
625
+ end
626
+ end
627
+
628
+ should "still have its #file attribute not be nil" do
629
+ assert ! (file = @attachment.to_file).nil?
630
+ file.close
631
+ end
632
+
633
+ context "and trying to delete" do
634
+ setup do
635
+ @existing_names = @attachment.styles.keys.collect do |style|
636
+ @attachment.path(style)
637
+ end
638
+ end
639
+
640
+ should "delete the files after assigning nil" do
641
+ @attachment.expects(:instance_write).with(:file_name, nil)
642
+ @attachment.expects(:instance_write).with(:content_type, nil)
643
+ @attachment.expects(:instance_write).with(:file_size, nil)
644
+ @attachment.expects(:instance_write).with(:updated_at, nil)
645
+ @attachment.assign nil
646
+ @attachment.save
647
+ @existing_names.each{|f| assert ! File.exists?(f) }
648
+ end
649
+
650
+ should "delete the files when you call #clear and #save" do
651
+ @attachment.expects(:instance_write).with(:file_name, nil)
652
+ @attachment.expects(:instance_write).with(:content_type, nil)
653
+ @attachment.expects(:instance_write).with(:file_size, nil)
654
+ @attachment.expects(:instance_write).with(:updated_at, nil)
655
+ @attachment.clear
656
+ @attachment.save
657
+ @existing_names.each{|f| assert ! File.exists?(f) }
658
+ end
659
+
660
+ should "delete the files when you call #delete" do
661
+ @attachment.expects(:instance_write).with(:file_name, nil)
662
+ @attachment.expects(:instance_write).with(:content_type, nil)
663
+ @attachment.expects(:instance_write).with(:file_size, nil)
664
+ @attachment.expects(:instance_write).with(:updated_at, nil)
665
+ @attachment.destroy
666
+ @existing_names.each{|f| assert ! File.exists?(f) }
667
+ end
668
+ end
669
+ end
670
+ end
671
+ end
672
+
673
+ end
674
+
675
+ context "when trying a nonexistant storage type" do
676
+ setup do
677
+ rebuild_model :storage => :not_here
678
+ end
679
+
680
+ should "not be able to find the module" do
681
+ assert_raise(Paperclip::StorageMethodNotFound){ Dummy.new.avatar }
682
+ end
683
+ end
684
+ end
685
+
686
+ context "An attachment with only a avatar_file_name column" do
687
+ setup do
688
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
689
+ table.column :avatar_file_name, :string
690
+ end
691
+ rebuild_class
692
+ @dummy = Dummy.new
693
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
694
+ end
695
+
696
+ teardown { @file.close }
697
+
698
+ should "not error when assigned an attachment" do
699
+ assert_nothing_raised { @dummy.avatar = @file }
700
+ end
701
+
702
+ should "return the time when sent #avatar_updated_at" do
703
+ now = Time.now
704
+ Time.stubs(:now).returns(now)
705
+ @dummy.avatar = @file
706
+ assert_equal now.to_i, @dummy.avatar.updated_at.to_i
707
+ end
708
+
709
+ should "return nil when reloaded and sent #avatar_updated_at" do
710
+ @dummy.save
711
+ @dummy.reload
712
+ assert_nil @dummy.avatar.updated_at
713
+ end
714
+
715
+ should "return the right value when sent #avatar_file_size" do
716
+ @dummy.avatar = @file
717
+ assert_equal @file.size, @dummy.avatar.size
718
+ end
719
+
720
+ context "and avatar_updated_at column" do
721
+ setup do
722
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_updated_at, :timestamp
723
+ rebuild_class
724
+ @dummy = Dummy.new
725
+ end
726
+
727
+ should "not error when assigned an attachment" do
728
+ assert_nothing_raised { @dummy.avatar = @file }
729
+ end
730
+
731
+ should "return the right value when sent #avatar_updated_at" do
732
+ now = Time.now
733
+ Time.stubs(:now).returns(now)
734
+ @dummy.avatar = @file
735
+ assert_equal now.to_i, @dummy.avatar.updated_at
736
+ end
737
+ end
738
+
739
+ context "and avatar_content_type column" do
740
+ setup do
741
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string
742
+ rebuild_class
743
+ @dummy = Dummy.new
744
+ end
745
+
746
+ should "not error when assigned an attachment" do
747
+ assert_nothing_raised { @dummy.avatar = @file }
748
+ end
749
+
750
+ should "return the right value when sent #avatar_content_type" do
751
+ @dummy.avatar = @file
752
+ assert_equal "image/png", @dummy.avatar.content_type
753
+ end
754
+ end
755
+
756
+ context "and avatar_file_size column" do
757
+ setup do
758
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer
759
+ rebuild_class
760
+ @dummy = Dummy.new
761
+ end
762
+
763
+ should "not error when assigned an attachment" do
764
+ assert_nothing_raised { @dummy.avatar = @file }
765
+ end
766
+
767
+ should "return the right value when sent #avatar_file_size" do
768
+ @dummy.avatar = @file
769
+ assert_equal @file.size, @dummy.avatar.size
770
+ end
771
+
772
+ should "return the right value when saved, reloaded, and sent #avatar_file_size" do
773
+ @dummy.avatar = @file
774
+ @dummy.save
775
+ @dummy = Dummy.find(@dummy.id)
776
+ assert_equal @file.size, @dummy.avatar.size
777
+ end
778
+ end
779
+
780
+ context "and avatar_fingerprint column" do
781
+ setup do
782
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_fingerprint, :string
783
+ rebuild_class
784
+ @dummy = Dummy.new
785
+ end
786
+
787
+ should "not error when assigned an attachment" do
788
+ assert_nothing_raised { @dummy.avatar = @file }
789
+ end
790
+
791
+ should "return the right value when sent #avatar_fingerprint" do
792
+ @dummy.avatar = @file
793
+ assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
794
+ end
795
+
796
+ should "return the right value when saved, reloaded, and sent #avatar_fingerprint" do
797
+ @dummy.avatar = @file
798
+ @dummy.save
799
+ @dummy = Dummy.find(@dummy.id)
800
+ assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
801
+ end
802
+ end
803
+ end
804
+ end