paperclip 3.0.3 → 3.5.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of paperclip might be problematic. Click here for more details.
- checksums.yaml +15 -0
- data/.gitignore +2 -1
- data/.travis.yml +3 -0
- data/Appraisals +8 -3
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/NEWS +198 -35
- data/README.md +332 -113
- data/features/basic_integration.feature +24 -12
- data/features/migration.feature +94 -0
- data/features/rake_tasks.feature +2 -3
- data/features/step_definitions/attachment_steps.rb +28 -0
- data/features/step_definitions/rails_steps.rb +94 -8
- data/features/step_definitions/s3_steps.rb +1 -1
- data/features/step_definitions/web_steps.rb +3 -3
- data/features/support/fakeweb.rb +4 -1
- data/features/support/file_helpers.rb +10 -0
- data/features/support/rails.rb +18 -2
- data/gemfiles/3.0.gemfile +2 -2
- data/gemfiles/3.1.gemfile +2 -2
- data/gemfiles/3.2.gemfile +2 -2
- data/gemfiles/4.0.gemfile +11 -0
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +4 -8
- data/lib/paperclip/attachment.rb +96 -43
- data/lib/paperclip/attachment_registry.rb +57 -0
- data/lib/paperclip/callbacks.rb +2 -2
- data/lib/paperclip/content_type_detector.rb +78 -0
- data/lib/paperclip/file_command_content_type_detector.rb +32 -0
- data/lib/paperclip/filename_cleaner.rb +16 -0
- data/lib/paperclip/geometry.rb +66 -30
- data/lib/paperclip/geometry_detector_factory.rb +41 -0
- data/lib/paperclip/geometry_parser_factory.rb +31 -0
- data/lib/paperclip/glue.rb +2 -8
- data/lib/paperclip/has_attached_file.rb +99 -0
- data/lib/paperclip/helpers.rb +12 -15
- data/lib/paperclip/interpolations/plural_cache.rb +17 -0
- data/lib/paperclip/interpolations.rb +15 -5
- data/lib/paperclip/io_adapters/abstract_adapter.rb +45 -0
- data/lib/paperclip/io_adapters/attachment_adapter.rb +14 -49
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +27 -0
- data/lib/paperclip/io_adapters/empty_string_adapter.rb +18 -0
- data/lib/paperclip/io_adapters/file_adapter.rb +8 -69
- data/lib/paperclip/io_adapters/identity_adapter.rb +1 -1
- data/lib/paperclip/io_adapters/nil_adapter.rb +2 -2
- data/lib/paperclip/io_adapters/stringio_adapter.rb +16 -45
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +17 -40
- data/lib/paperclip/io_adapters/uri_adapter.rb +44 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +1 -5
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +36 -17
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +5 -1
- data/lib/paperclip/matchers.rb +3 -3
- data/lib/paperclip/missing_attachment_styles.rb +11 -16
- data/lib/paperclip/processor.rb +12 -0
- data/lib/paperclip/railtie.rb +5 -1
- data/lib/paperclip/schema.rb +59 -23
- data/lib/paperclip/storage/filesystem.rb +23 -5
- data/lib/paperclip/storage/fog.rb +64 -25
- data/lib/paperclip/storage/s3.rb +93 -52
- data/lib/paperclip/style.rb +2 -2
- data/lib/paperclip/tempfile_factory.rb +21 -0
- data/lib/paperclip/thumbnail.rb +18 -3
- data/lib/paperclip/validators/attachment_content_type_validator.rb +38 -10
- data/lib/paperclip/validators/attachment_presence_validator.rb +8 -8
- data/lib/paperclip/validators/attachment_size_validator.rb +12 -7
- data/lib/paperclip/validators.rb +21 -2
- data/lib/paperclip/version.rb +1 -1
- data/lib/paperclip.rb +15 -44
- data/lib/tasks/paperclip.rake +26 -7
- data/paperclip.gemspec +11 -7
- data/test/attachment_definitions_test.rb +12 -0
- data/test/attachment_processing_test.rb +83 -0
- data/test/attachment_registry_test.rb +77 -0
- data/test/attachment_test.rb +253 -44
- data/test/content_type_detector_test.rb +50 -0
- data/test/file_command_content_type_detector_test.rb +25 -0
- data/test/filename_cleaner_test.rb +14 -0
- data/test/fixtures/animated +0 -0
- data/test/fixtures/animated.unknown +0 -0
- data/test/fixtures/rotated.jpg +0 -0
- data/test/generator_test.rb +26 -24
- data/test/geometry_detector_test.rb +24 -0
- data/test/geometry_parser_test.rb +73 -0
- data/test/geometry_test.rb +55 -4
- data/test/has_attached_file_test.rb +125 -0
- data/test/helper.rb +38 -7
- data/test/integration_test.rb +105 -89
- data/test/interpolations_test.rb +12 -0
- data/test/io_adapters/abstract_adapter_test.rb +58 -0
- data/test/io_adapters/attachment_adapter_test.rb +120 -33
- data/test/io_adapters/data_uri_adapter_test.rb +60 -0
- data/test/io_adapters/empty_string_adapter_test.rb +17 -0
- data/test/io_adapters/file_adapter_test.rb +32 -1
- data/test/io_adapters/stringio_adapter_test.rb +29 -10
- data/test/io_adapters/uploaded_file_adapter_test.rb +53 -5
- data/test/io_adapters/uri_adapter_test.rb +102 -0
- data/test/matchers/validate_attachment_presence_matcher_test.rb +22 -0
- data/test/meta_class_test.rb +32 -0
- data/test/paperclip_missing_attachment_styles_test.rb +4 -8
- data/test/paperclip_test.rb +27 -51
- data/test/plural_cache_test.rb +36 -0
- data/test/processor_test.rb +16 -0
- data/test/rake_test.rb +103 -0
- data/test/schema_test.rb +179 -77
- data/test/storage/filesystem_test.rb +26 -3
- data/test/storage/fog_test.rb +181 -3
- data/test/storage/s3_test.rb +239 -4
- data/test/style_test.rb +18 -14
- data/test/tempfile_factory_test.rb +13 -0
- data/test/thumbnail_test.rb +96 -16
- data/test/validators/attachment_content_type_validator_test.rb +181 -55
- data/test/validators/attachment_size_validator_test.rb +10 -0
- data/test/validators_test.rb +8 -1
- metadata +126 -92
- data/Gemfile.lock +0 -157
- data/features/support/fixtures/.boot_config.rb.swo +0 -0
- data/images.rake +0 -21
- data/lib/.DS_Store +0 -0
- data/lib/paperclip/.DS_Store +0 -0
- data/lib/paperclip/attachment_options.rb +0 -9
- data/lib/paperclip/instance_methods.rb +0 -35
- data/test/attachment_options_test.rb +0 -27
data/test/integration_test.rb
CHANGED
@@ -96,14 +96,14 @@ class IntegrationTest < Test::Unit::TestCase
|
|
96
96
|
@dummy.avatar.post_processing = false
|
97
97
|
@dummy.avatar = @file
|
98
98
|
assert @dummy.save
|
99
|
-
|
99
|
+
assert_file_not_exists @thumb_path
|
100
100
|
end
|
101
101
|
|
102
102
|
should "create the thumbnails upon saving when post_processing is enabled" do
|
103
103
|
@dummy.avatar.post_processing = true
|
104
104
|
@dummy.avatar = @file
|
105
105
|
assert @dummy.save
|
106
|
-
|
106
|
+
assert_file_exists @thumb_path
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
@@ -126,25 +126,25 @@ class IntegrationTest < Test::Unit::TestCase
|
|
126
126
|
teardown { @file.close }
|
127
127
|
|
128
128
|
should "allow us to create all thumbnails in one go" do
|
129
|
-
|
130
|
-
|
129
|
+
assert_file_not_exists(@thumb_small_path)
|
130
|
+
assert_file_not_exists(@thumb_large_path)
|
131
131
|
|
132
132
|
@dummy.avatar.reprocess!
|
133
133
|
|
134
|
-
|
135
|
-
|
134
|
+
assert_file_exists(@thumb_small_path)
|
135
|
+
assert_file_exists(@thumb_large_path)
|
136
136
|
end
|
137
137
|
|
138
138
|
should "allow us to selectively create each thumbnail" do
|
139
|
-
|
140
|
-
|
139
|
+
assert_file_not_exists(@thumb_small_path)
|
140
|
+
assert_file_not_exists(@thumb_large_path)
|
141
141
|
|
142
142
|
@dummy.avatar.reprocess! :thumb_small
|
143
|
-
|
144
|
-
|
143
|
+
assert_file_exists(@thumb_small_path)
|
144
|
+
assert_file_not_exists(@thumb_large_path)
|
145
145
|
|
146
146
|
@dummy.avatar.reprocess! :thumb_large
|
147
|
-
|
147
|
+
assert_file_exists(@thumb_large_path)
|
148
148
|
end
|
149
149
|
end
|
150
150
|
|
@@ -182,7 +182,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
182
182
|
end
|
183
183
|
|
184
184
|
should "have a large file in the right place" do
|
185
|
-
|
185
|
+
assert_file_exists(@dummy.avatar.path(:large))
|
186
186
|
end
|
187
187
|
|
188
188
|
context "and deleted" do
|
@@ -192,12 +192,12 @@ class IntegrationTest < Test::Unit::TestCase
|
|
192
192
|
end
|
193
193
|
|
194
194
|
should "not have a large file in the right place anymore" do
|
195
|
-
|
195
|
+
assert_file_not_exists(@saved_path)
|
196
196
|
end
|
197
197
|
|
198
198
|
should "not have its next two parent directories" do
|
199
|
-
|
200
|
-
|
199
|
+
assert_file_not_exists(File.dirname(@saved_path))
|
200
|
+
assert_file_not_exists(File.dirname(File.dirname(@saved_path)))
|
201
201
|
end
|
202
202
|
|
203
203
|
before_should "not die if an unexpected SystemCallError happens" do
|
@@ -207,92 +207,57 @@ class IntegrationTest < Test::Unit::TestCase
|
|
207
207
|
end
|
208
208
|
end
|
209
209
|
|
210
|
-
|
211
|
-
|
212
|
-
rebuild_model :styles => { :large => "300x300>",
|
213
|
-
:medium => "100x100",
|
214
|
-
:thumb => ["32x32#", :gif] },
|
215
|
-
:default_style => :medium,
|
216
|
-
:url => "/:attachment/:class/:style/:id/:basename.:extension",
|
217
|
-
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
218
|
-
@dummy = Dummy.new
|
219
|
-
end
|
220
|
-
|
221
|
-
should "have its definition return nil when asked about convert_options" do
|
222
|
-
assert ! Dummy.attachment_definitions[:avatar][:convert_options]
|
223
|
-
end
|
224
|
-
|
225
|
-
context "redefined to have convert_options setting" do
|
210
|
+
[000,002,022].each do |umask|
|
211
|
+
context "when the umask is #{umask}" do
|
226
212
|
setup do
|
227
|
-
rebuild_model
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
:default_style => :medium,
|
232
|
-
:url => "/:attachment/:class/:style/:id/:basename.:extension",
|
233
|
-
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
234
|
-
end
|
235
|
-
|
236
|
-
should "have its definition return convert_options value when asked about convert_options" do
|
237
|
-
assert_equal "-strip -depth 8", Dummy.attachment_definitions[:avatar][:convert_options]
|
213
|
+
rebuild_model
|
214
|
+
@dummy = Dummy.new
|
215
|
+
@file = File.new(fixture_file("5k.png"), 'rb')
|
216
|
+
@umask = File.umask(umask)
|
238
217
|
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
context "A model with no source_file_options setting" do
|
243
|
-
setup do
|
244
|
-
rebuild_model :styles => { :large => "300x300>",
|
245
|
-
:medium => "100x100",
|
246
|
-
:thumb => ["32x32#", :gif] },
|
247
|
-
:default_style => :medium,
|
248
|
-
:url => "/:attachment/:class/:style/:id/:basename.:extension",
|
249
|
-
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
250
|
-
@dummy = Dummy.new
|
251
|
-
end
|
252
218
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
context "redefined to have source_file_options setting" do
|
258
|
-
setup do
|
259
|
-
rebuild_model :styles => { :large => "300x300>",
|
260
|
-
:medium => "100x100",
|
261
|
-
:thumb => ["32x32#", :gif] },
|
262
|
-
:source_file_options => "-density 400",
|
263
|
-
:default_style => :medium,
|
264
|
-
:url => "/:attachment/:class/:style/:id/:basename.:extension",
|
265
|
-
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
219
|
+
teardown do
|
220
|
+
File.umask @umask
|
221
|
+
@file.close
|
266
222
|
end
|
267
223
|
|
268
|
-
should "
|
269
|
-
|
224
|
+
should "respect the current umask" do
|
225
|
+
@dummy.avatar = @file
|
226
|
+
@dummy.save
|
227
|
+
assert_equal 0666&~umask, 0666&File.stat(@dummy.avatar.path).mode
|
270
228
|
end
|
271
229
|
end
|
272
230
|
end
|
273
231
|
|
274
|
-
[
|
275
|
-
context "when the
|
232
|
+
[0666,0664,0640].each do |perms|
|
233
|
+
context "when the perms are #{perms}" do
|
276
234
|
setup do
|
277
|
-
rebuild_model
|
235
|
+
rebuild_model :override_file_permissions => perms
|
278
236
|
@dummy = Dummy.new
|
279
237
|
@file = File.new(fixture_file("5k.png"), 'rb')
|
280
|
-
@umask = File.umask(umask)
|
281
238
|
end
|
282
239
|
|
283
240
|
teardown do
|
284
|
-
File.umask @umask
|
285
241
|
@file.close
|
286
242
|
end
|
287
243
|
|
288
|
-
should "respect the current
|
244
|
+
should "respect the current perms" do
|
289
245
|
@dummy.avatar = @file
|
290
246
|
@dummy.save
|
291
|
-
assert_equal
|
247
|
+
assert_equal perms, File.stat(@dummy.avatar.path).mode & 0777
|
292
248
|
end
|
293
249
|
end
|
294
250
|
end
|
295
251
|
|
252
|
+
should "skip chmod operation, when override_file_permissions is set to false (e.g. useful when using CIFS mounts)" do
|
253
|
+
FileUtils.expects(:chmod).never
|
254
|
+
|
255
|
+
rebuild_model :override_file_permissions => false
|
256
|
+
dummy = Dummy.create!
|
257
|
+
dummy.avatar = @file
|
258
|
+
dummy.save
|
259
|
+
end
|
260
|
+
|
296
261
|
context "A model with a filesystem attachment" do
|
297
262
|
setup do
|
298
263
|
rebuild_model :styles => { :large => "300x300>",
|
@@ -334,7 +299,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
334
299
|
assert @dummy.save
|
335
300
|
|
336
301
|
saved_paths.each do |p|
|
337
|
-
|
302
|
+
assert_file_exists(p)
|
338
303
|
end
|
339
304
|
|
340
305
|
@dummy.avatar.clear
|
@@ -343,7 +308,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
343
308
|
assert @dummy.save
|
344
309
|
|
345
310
|
saved_paths.each do |p|
|
346
|
-
|
311
|
+
assert_file_not_exists(p)
|
347
312
|
end
|
348
313
|
|
349
314
|
@d2 = Dummy.find(@dummy.id)
|
@@ -364,7 +329,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
364
329
|
assert @d2.save
|
365
330
|
|
366
331
|
saved_paths.each do |p|
|
367
|
-
|
332
|
+
assert_file_not_exists(p)
|
368
333
|
end
|
369
334
|
end
|
370
335
|
|
@@ -383,7 +348,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
383
348
|
Dummy.validates_attachment_presence :avatar
|
384
349
|
@d2 = Dummy.find(@dummy.id)
|
385
350
|
@d2.avatar = @file
|
386
|
-
assert
|
351
|
+
assert @d2.valid?, @d2.errors.full_messages.inspect
|
387
352
|
@d2.avatar = @bad_file
|
388
353
|
assert ! @d2.valid?
|
389
354
|
end
|
@@ -457,21 +422,23 @@ class IntegrationTest < Test::Unit::TestCase
|
|
457
422
|
end
|
458
423
|
|
459
424
|
should "be accessible" do
|
460
|
-
|
461
|
-
|
425
|
+
assert_file_exists(@dummy.avatar.path(:original))
|
426
|
+
assert_file_exists(@dummy.avatar.path(:thumb))
|
462
427
|
end
|
463
428
|
|
464
429
|
context "when new style is added" do
|
465
430
|
setup do
|
466
431
|
@dummy.avatar.options[:styles][:mini] = "25x25#"
|
467
432
|
@dummy.avatar.instance_variable_set :@normalized_styles, nil
|
468
|
-
|
433
|
+
Time.stubs(:now => Time.now + 10)
|
434
|
+
@dummy.avatar.reprocess!
|
435
|
+
@dummy.reload
|
469
436
|
end
|
470
437
|
|
471
438
|
should "make all the styles accessible" do
|
472
|
-
|
473
|
-
|
474
|
-
|
439
|
+
assert_file_exists(@dummy.avatar.path(:original))
|
440
|
+
assert_file_exists(@dummy.avatar.path(:thumb))
|
441
|
+
assert_file_exists(@dummy.avatar.path(:mini))
|
475
442
|
end
|
476
443
|
end
|
477
444
|
end
|
@@ -501,7 +468,13 @@ class IntegrationTest < Test::Unit::TestCase
|
|
501
468
|
setup do
|
502
469
|
rebuild_model :styles => { :large => "300x300>",
|
503
470
|
:medium => "100x100",
|
504
|
-
:thumb => ["32x32#", :gif]
|
471
|
+
:thumb => ["32x32#", :gif],
|
472
|
+
:custom => {
|
473
|
+
:geometry => "32x32#",
|
474
|
+
:s3_headers => { 'Cache-Control' => 'max-age=31557600' },
|
475
|
+
:s3_metadata => { 'foo' => 'bar'}
|
476
|
+
}
|
477
|
+
},
|
505
478
|
:storage => :s3,
|
506
479
|
:s3_credentials => File.new(fixture_file('s3.yml')),
|
507
480
|
:s3_options => { :logger => Paperclip.logger },
|
@@ -628,9 +601,18 @@ class IntegrationTest < Test::Unit::TestCase
|
|
628
601
|
assert_equal 'image/png', headers['content-type']
|
629
602
|
end
|
630
603
|
|
604
|
+
should "have the right style-specific headers" do
|
605
|
+
headers = s3_headers_for(@dummy.avatar, :custom)
|
606
|
+
assert_equal 'max-age=31557600', headers['cache-control']
|
607
|
+
end
|
608
|
+
|
609
|
+
should "have the right style-specific metadata" do
|
610
|
+
headers = s3_headers_for(@dummy.avatar, :custom)
|
611
|
+
assert_equal 'bar', headers['x-amz-meta-foo']
|
612
|
+
end
|
613
|
+
|
631
614
|
context "with non-english character in the file name" do
|
632
615
|
setup do
|
633
|
-
|
634
616
|
@file.stubs(:original_filename).returns("クリップ.png")
|
635
617
|
@dummy.avatar = @file
|
636
618
|
end
|
@@ -641,4 +623,38 @@ class IntegrationTest < Test::Unit::TestCase
|
|
641
623
|
end
|
642
624
|
end
|
643
625
|
end
|
626
|
+
|
627
|
+
context "Copying attachments between models" do
|
628
|
+
setup do
|
629
|
+
rebuild_model
|
630
|
+
@file = File.new(fixture_file("5k.png"), 'rb')
|
631
|
+
end
|
632
|
+
|
633
|
+
teardown { @file.close }
|
634
|
+
|
635
|
+
should "succeed when original attachment is a file" do
|
636
|
+
original = Dummy.new
|
637
|
+
original.avatar = @file
|
638
|
+
assert original.save
|
639
|
+
|
640
|
+
copy = Dummy.new
|
641
|
+
copy.avatar = original.avatar
|
642
|
+
assert copy.save
|
643
|
+
|
644
|
+
assert copy.avatar.present?
|
645
|
+
end
|
646
|
+
|
647
|
+
should "succeed when original attachment is empty" do
|
648
|
+
original = Dummy.create!
|
649
|
+
|
650
|
+
copy = Dummy.new
|
651
|
+
copy.avatar = @file
|
652
|
+
assert copy.save
|
653
|
+
assert copy.avatar.present?
|
654
|
+
|
655
|
+
copy.avatar = original.avatar
|
656
|
+
assert copy.save
|
657
|
+
assert !copy.avatar.present?
|
658
|
+
end
|
659
|
+
end
|
644
660
|
end
|
data/test/interpolations_test.rb
CHANGED
@@ -56,6 +56,7 @@ class InterpolationsTest < Test::Unit::TestCase
|
|
56
56
|
should "return the extension of the file based on the content type" do
|
57
57
|
attachment = mock
|
58
58
|
attachment.expects(:content_type).returns('image/jpeg')
|
59
|
+
attachment.expects(:styles).returns({})
|
59
60
|
interpolations = Paperclip::Interpolations
|
60
61
|
interpolations.expects(:extension).returns('random')
|
61
62
|
assert_equal "jpeg", interpolations.content_type_extension(attachment, :style)
|
@@ -64,6 +65,7 @@ class InterpolationsTest < Test::Unit::TestCase
|
|
64
65
|
should "return the original extension of the file if it matches a content type extension" do
|
65
66
|
attachment = mock
|
66
67
|
attachment.expects(:content_type).returns('image/jpeg')
|
68
|
+
attachment.expects(:styles).returns({})
|
67
69
|
interpolations = Paperclip::Interpolations
|
68
70
|
interpolations.expects(:extension).returns('jpe')
|
69
71
|
assert_equal "jpe", interpolations.content_type_extension(attachment, :style)
|
@@ -72,11 +74,21 @@ class InterpolationsTest < Test::Unit::TestCase
|
|
72
74
|
should "return the latter half of the content type of the extension if no match found" do
|
73
75
|
attachment = mock
|
74
76
|
attachment.expects(:content_type).at_least_once().returns('not/found')
|
77
|
+
attachment.expects(:styles).returns({})
|
75
78
|
interpolations = Paperclip::Interpolations
|
76
79
|
interpolations.expects(:extension).returns('random')
|
77
80
|
assert_equal "found", interpolations.content_type_extension(attachment, :style)
|
78
81
|
end
|
79
82
|
|
83
|
+
should "return the format if defined in the style, ignoring the content type" do
|
84
|
+
attachment = mock
|
85
|
+
attachment.expects(:content_type).returns('image/jpeg')
|
86
|
+
attachment.expects(:styles).returns({:style => {:format => "png"}})
|
87
|
+
interpolations = Paperclip::Interpolations
|
88
|
+
interpolations.expects(:extension).returns('random')
|
89
|
+
assert_equal "png", interpolations.content_type_extension(attachment, :style)
|
90
|
+
end
|
91
|
+
|
80
92
|
should "be able to handle numeric style names" do
|
81
93
|
attachment = mock(
|
82
94
|
:styles => {:"4" => {:format => :expected_extension}}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require './test/helper'
|
2
|
+
|
3
|
+
class AbstractAdapterTest < Test::Unit::TestCase
|
4
|
+
class TestAdapter < Paperclip::AbstractAdapter
|
5
|
+
attr_accessor :tempfile
|
6
|
+
|
7
|
+
def content_type
|
8
|
+
Paperclip::ContentTypeDetector.new(path).detect
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "content type from file command" do
|
13
|
+
setup do
|
14
|
+
@adapter = TestAdapter.new
|
15
|
+
@adapter.stubs(:path).returns("image.png")
|
16
|
+
end
|
17
|
+
|
18
|
+
should "return the content type without newline" do
|
19
|
+
assert_equal "image/png", @adapter.content_type
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "nil?" do
|
24
|
+
should "return false" do
|
25
|
+
assert !TestAdapter.new.nil?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "delegation" do
|
30
|
+
setup do
|
31
|
+
@adapter = TestAdapter.new
|
32
|
+
@adapter.tempfile = stub("Tempfile")
|
33
|
+
end
|
34
|
+
|
35
|
+
[:close, :closed?, :eof?, :path, :rewind, :unlink].each do |method|
|
36
|
+
should "delegate #{method} to @tempfile" do
|
37
|
+
@adapter.tempfile.stubs(method)
|
38
|
+
@adapter.public_send(method)
|
39
|
+
assert_received @adapter.tempfile, method
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
should 'get rid of slashes and colons in filenames' do
|
45
|
+
@adapter = TestAdapter.new
|
46
|
+
@adapter.original_filename = "awesome/file:name.png"
|
47
|
+
|
48
|
+
assert_equal "awesome_file_name.png", @adapter.original_filename
|
49
|
+
end
|
50
|
+
|
51
|
+
should 'be an assignment' do
|
52
|
+
assert TestAdapter.new.assignment?
|
53
|
+
end
|
54
|
+
|
55
|
+
should 'not be nil' do
|
56
|
+
assert !TestAdapter.new.nil?
|
57
|
+
end
|
58
|
+
end
|
@@ -1,51 +1,138 @@
|
|
1
1
|
require './test/helper'
|
2
2
|
|
3
3
|
class AttachmentAdapterTest < Test::Unit::TestCase
|
4
|
+
|
4
5
|
def setup
|
5
|
-
rebuild_model :path => "tmp/:class/:attachment/:style/:filename"
|
6
|
+
rebuild_model :path => "tmp/:class/:attachment/:style/:filename", :styles => {:thumb => '50x50'}
|
6
7
|
@attachment = Dummy.new.avatar
|
7
|
-
@file = File.new(fixture_file("5k.png"))
|
8
|
-
@file.binmode
|
9
|
-
|
10
|
-
@attachment.assign(@file)
|
11
|
-
@attachment.save
|
12
|
-
@subject = Paperclip.io_adapters.for(@attachment)
|
13
8
|
end
|
14
9
|
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
context "for an attachment" do
|
11
|
+
setup do
|
12
|
+
@file = File.new(fixture_file("5k.png"))
|
13
|
+
@file.binmode
|
18
14
|
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
@attachment.assign(@file)
|
16
|
+
@attachment.save
|
17
|
+
@subject = Paperclip.io_adapters.for(@attachment)
|
18
|
+
end
|
22
19
|
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
teardown do
|
21
|
+
@file.close
|
22
|
+
end
|
26
23
|
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
should "get the right filename" do
|
25
|
+
assert_equal "5k.png", @subject.original_filename
|
26
|
+
end
|
30
27
|
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
should "force binmode on tempfile" do
|
29
|
+
assert @subject.instance_variable_get("@tempfile").binmode?
|
30
|
+
end
|
31
|
+
|
32
|
+
should "get the content type" do
|
33
|
+
assert_equal "image/png", @subject.content_type
|
34
|
+
end
|
35
|
+
|
36
|
+
should "get the file's size" do
|
37
|
+
assert_equal 4456, @subject.size
|
38
|
+
end
|
39
|
+
|
40
|
+
should "return false for a call to nil?" do
|
41
|
+
assert ! @subject.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
should "generate a MD5 hash of the contents" do
|
45
|
+
expected = Digest::MD5.file(@file.path).to_s
|
46
|
+
assert_equal expected, @subject.fingerprint
|
47
|
+
end
|
48
|
+
|
49
|
+
should "read the contents of the file" do
|
50
|
+
expected = @file.read
|
51
|
+
actual = @subject.read
|
52
|
+
assert expected.length > 0
|
53
|
+
assert_equal expected.length, actual.length
|
54
|
+
assert_equal expected, actual
|
55
|
+
end
|
34
56
|
|
35
|
-
should "return false for a call to nil?" do
|
36
|
-
assert ! @subject.nil?
|
37
57
|
end
|
38
58
|
|
39
|
-
|
40
|
-
|
41
|
-
|
59
|
+
context "for a file with restricted characters in the name" do
|
60
|
+
setup do
|
61
|
+
file_contents = File.new(fixture_file("animated.gif"))
|
62
|
+
@file = StringIO.new(file_contents.read)
|
63
|
+
@file.stubs(:original_filename).returns('image:restricted.gif')
|
64
|
+
@file.binmode
|
65
|
+
|
66
|
+
@attachment.assign(@file)
|
67
|
+
@attachment.save
|
68
|
+
@subject = Paperclip.io_adapters.for(@attachment)
|
69
|
+
end
|
70
|
+
|
71
|
+
teardown do
|
72
|
+
@file.close
|
73
|
+
end
|
74
|
+
|
75
|
+
should "not generate paths that include restricted characters" do
|
76
|
+
assert_no_match /:/, @subject.path
|
77
|
+
end
|
78
|
+
|
79
|
+
should "not generate filenames that include restricted characters" do
|
80
|
+
assert_equal 'image_restricted.gif', @subject.original_filename
|
81
|
+
end
|
42
82
|
end
|
43
83
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
84
|
+
context "for a style" do
|
85
|
+
setup do
|
86
|
+
@file = File.new(fixture_file("5k.png"))
|
87
|
+
@file.binmode
|
88
|
+
|
89
|
+
@attachment.assign(@file)
|
90
|
+
|
91
|
+
@thumb = Tempfile.new("thumbnail").tap(&:binmode)
|
92
|
+
FileUtils.cp @attachment.queued_for_write[:thumb].path, @thumb.path
|
93
|
+
|
94
|
+
@attachment.save
|
95
|
+
@subject = Paperclip.io_adapters.for(@attachment.styles[:thumb])
|
96
|
+
end
|
97
|
+
|
98
|
+
teardown do
|
99
|
+
@file.close
|
100
|
+
@thumb.close
|
101
|
+
end
|
102
|
+
|
103
|
+
should "get the original filename" do
|
104
|
+
assert_equal "5k.png", @subject.original_filename
|
105
|
+
end
|
106
|
+
|
107
|
+
should "force binmode on tempfile" do
|
108
|
+
assert @subject.instance_variable_get("@tempfile").binmode?
|
109
|
+
end
|
110
|
+
|
111
|
+
should "get the content type" do
|
112
|
+
assert_equal "image/png", @subject.content_type
|
113
|
+
end
|
114
|
+
|
115
|
+
should "get the thumbnail's file size" do
|
116
|
+
assert_equal @thumb.size, @subject.size
|
117
|
+
end
|
118
|
+
|
119
|
+
should "return false for a call to nil?" do
|
120
|
+
assert ! @subject.nil?
|
121
|
+
end
|
122
|
+
|
123
|
+
should "generate a MD5 hash of the contents" do
|
124
|
+
expected = Digest::MD5.file(@thumb.path).to_s
|
125
|
+
assert_equal expected, @subject.fingerprint
|
126
|
+
end
|
127
|
+
|
128
|
+
should "read the contents of the thumbnail" do
|
129
|
+
@thumb.rewind
|
130
|
+
expected = @thumb.read
|
131
|
+
actual = @subject.read
|
132
|
+
assert expected.length > 0
|
133
|
+
assert_equal expected.length, actual.length
|
134
|
+
assert_equal expected, actual
|
135
|
+
end
|
136
|
+
|
50
137
|
end
|
51
138
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require './test/helper'
|
2
|
+
|
3
|
+
class DataUriAdapterTest < Test::Unit::TestCase
|
4
|
+
context "a new instance" do
|
5
|
+
setup do
|
6
|
+
@contents = "data:image/png;base64,dGVzdA=="
|
7
|
+
@subject = Paperclip.io_adapters.for(@contents)
|
8
|
+
end
|
9
|
+
|
10
|
+
should "return a file name" do
|
11
|
+
assert_equal "base64.txt", @subject.original_filename
|
12
|
+
end
|
13
|
+
|
14
|
+
should "return a content type" do
|
15
|
+
assert_equal "image/png", @subject.content_type
|
16
|
+
end
|
17
|
+
|
18
|
+
should "return the size of the data" do
|
19
|
+
assert_equal 4, @subject.size
|
20
|
+
end
|
21
|
+
|
22
|
+
should "generate an MD5 hash of the contents" do
|
23
|
+
assert_equal Digest::MD5.hexdigest(Base64.decode64('dGVzdA==')), @subject.fingerprint
|
24
|
+
end
|
25
|
+
|
26
|
+
should "generate correct fingerprint after read" do
|
27
|
+
fingerprint = Digest::MD5.hexdigest(@subject.read)
|
28
|
+
assert_equal fingerprint, @subject.fingerprint
|
29
|
+
end
|
30
|
+
|
31
|
+
should "generate same fingerprint" do
|
32
|
+
assert_equal @subject.fingerprint, @subject.fingerprint
|
33
|
+
end
|
34
|
+
|
35
|
+
should "return the data contained in the StringIO" do
|
36
|
+
assert_equal "test", @subject.read
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'accept a content_type' do
|
40
|
+
@subject.content_type = 'image/png'
|
41
|
+
assert_equal 'image/png', @subject.content_type
|
42
|
+
end
|
43
|
+
|
44
|
+
should 'accept an original_filename' do
|
45
|
+
@subject.original_filename = 'image.png'
|
46
|
+
assert_equal 'image.png', @subject.original_filename
|
47
|
+
end
|
48
|
+
|
49
|
+
should "not generate filenames that include restricted characters" do
|
50
|
+
@subject.original_filename = 'image:restricted.png'
|
51
|
+
assert_equal 'image_restricted.png', @subject.original_filename
|
52
|
+
end
|
53
|
+
|
54
|
+
should "not generate paths that include restricted characters" do
|
55
|
+
@subject.original_filename = 'image:restricted.png'
|
56
|
+
assert_no_match /:/, @subject.path
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require './test/helper'
|
2
|
+
|
3
|
+
class EmptyStringAdapterTest < Test::Unit::TestCase
|
4
|
+
context 'a new instance' do
|
5
|
+
setup do
|
6
|
+
@subject = Paperclip.io_adapters.for('')
|
7
|
+
end
|
8
|
+
|
9
|
+
should "return false for a call to nil?" do
|
10
|
+
assert !@subject.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
should 'return false for a call to assignment?' do
|
14
|
+
assert !@subject.assignment?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|