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.

Files changed (121) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +2 -1
  3. data/.travis.yml +3 -0
  4. data/Appraisals +8 -3
  5. data/Gemfile +1 -1
  6. data/LICENSE +1 -1
  7. data/NEWS +198 -35
  8. data/README.md +332 -113
  9. data/features/basic_integration.feature +24 -12
  10. data/features/migration.feature +94 -0
  11. data/features/rake_tasks.feature +2 -3
  12. data/features/step_definitions/attachment_steps.rb +28 -0
  13. data/features/step_definitions/rails_steps.rb +94 -8
  14. data/features/step_definitions/s3_steps.rb +1 -1
  15. data/features/step_definitions/web_steps.rb +3 -3
  16. data/features/support/fakeweb.rb +4 -1
  17. data/features/support/file_helpers.rb +10 -0
  18. data/features/support/rails.rb +18 -2
  19. data/gemfiles/3.0.gemfile +2 -2
  20. data/gemfiles/3.1.gemfile +2 -2
  21. data/gemfiles/3.2.gemfile +2 -2
  22. data/gemfiles/4.0.gemfile +11 -0
  23. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +4 -8
  24. data/lib/paperclip/attachment.rb +96 -43
  25. data/lib/paperclip/attachment_registry.rb +57 -0
  26. data/lib/paperclip/callbacks.rb +2 -2
  27. data/lib/paperclip/content_type_detector.rb +78 -0
  28. data/lib/paperclip/file_command_content_type_detector.rb +32 -0
  29. data/lib/paperclip/filename_cleaner.rb +16 -0
  30. data/lib/paperclip/geometry.rb +66 -30
  31. data/lib/paperclip/geometry_detector_factory.rb +41 -0
  32. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  33. data/lib/paperclip/glue.rb +2 -8
  34. data/lib/paperclip/has_attached_file.rb +99 -0
  35. data/lib/paperclip/helpers.rb +12 -15
  36. data/lib/paperclip/interpolations/plural_cache.rb +17 -0
  37. data/lib/paperclip/interpolations.rb +15 -5
  38. data/lib/paperclip/io_adapters/abstract_adapter.rb +45 -0
  39. data/lib/paperclip/io_adapters/attachment_adapter.rb +14 -49
  40. data/lib/paperclip/io_adapters/data_uri_adapter.rb +27 -0
  41. data/lib/paperclip/io_adapters/empty_string_adapter.rb +18 -0
  42. data/lib/paperclip/io_adapters/file_adapter.rb +8 -69
  43. data/lib/paperclip/io_adapters/identity_adapter.rb +1 -1
  44. data/lib/paperclip/io_adapters/nil_adapter.rb +2 -2
  45. data/lib/paperclip/io_adapters/stringio_adapter.rb +16 -45
  46. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +17 -40
  47. data/lib/paperclip/io_adapters/uri_adapter.rb +44 -0
  48. data/lib/paperclip/matchers/have_attached_file_matcher.rb +1 -5
  49. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +36 -17
  50. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +5 -1
  51. data/lib/paperclip/matchers.rb +3 -3
  52. data/lib/paperclip/missing_attachment_styles.rb +11 -16
  53. data/lib/paperclip/processor.rb +12 -0
  54. data/lib/paperclip/railtie.rb +5 -1
  55. data/lib/paperclip/schema.rb +59 -23
  56. data/lib/paperclip/storage/filesystem.rb +23 -5
  57. data/lib/paperclip/storage/fog.rb +64 -25
  58. data/lib/paperclip/storage/s3.rb +93 -52
  59. data/lib/paperclip/style.rb +2 -2
  60. data/lib/paperclip/tempfile_factory.rb +21 -0
  61. data/lib/paperclip/thumbnail.rb +18 -3
  62. data/lib/paperclip/validators/attachment_content_type_validator.rb +38 -10
  63. data/lib/paperclip/validators/attachment_presence_validator.rb +8 -8
  64. data/lib/paperclip/validators/attachment_size_validator.rb +12 -7
  65. data/lib/paperclip/validators.rb +21 -2
  66. data/lib/paperclip/version.rb +1 -1
  67. data/lib/paperclip.rb +15 -44
  68. data/lib/tasks/paperclip.rake +26 -7
  69. data/paperclip.gemspec +11 -7
  70. data/test/attachment_definitions_test.rb +12 -0
  71. data/test/attachment_processing_test.rb +83 -0
  72. data/test/attachment_registry_test.rb +77 -0
  73. data/test/attachment_test.rb +253 -44
  74. data/test/content_type_detector_test.rb +50 -0
  75. data/test/file_command_content_type_detector_test.rb +25 -0
  76. data/test/filename_cleaner_test.rb +14 -0
  77. data/test/fixtures/animated +0 -0
  78. data/test/fixtures/animated.unknown +0 -0
  79. data/test/fixtures/rotated.jpg +0 -0
  80. data/test/generator_test.rb +26 -24
  81. data/test/geometry_detector_test.rb +24 -0
  82. data/test/geometry_parser_test.rb +73 -0
  83. data/test/geometry_test.rb +55 -4
  84. data/test/has_attached_file_test.rb +125 -0
  85. data/test/helper.rb +38 -7
  86. data/test/integration_test.rb +105 -89
  87. data/test/interpolations_test.rb +12 -0
  88. data/test/io_adapters/abstract_adapter_test.rb +58 -0
  89. data/test/io_adapters/attachment_adapter_test.rb +120 -33
  90. data/test/io_adapters/data_uri_adapter_test.rb +60 -0
  91. data/test/io_adapters/empty_string_adapter_test.rb +17 -0
  92. data/test/io_adapters/file_adapter_test.rb +32 -1
  93. data/test/io_adapters/stringio_adapter_test.rb +29 -10
  94. data/test/io_adapters/uploaded_file_adapter_test.rb +53 -5
  95. data/test/io_adapters/uri_adapter_test.rb +102 -0
  96. data/test/matchers/validate_attachment_presence_matcher_test.rb +22 -0
  97. data/test/meta_class_test.rb +32 -0
  98. data/test/paperclip_missing_attachment_styles_test.rb +4 -8
  99. data/test/paperclip_test.rb +27 -51
  100. data/test/plural_cache_test.rb +36 -0
  101. data/test/processor_test.rb +16 -0
  102. data/test/rake_test.rb +103 -0
  103. data/test/schema_test.rb +179 -77
  104. data/test/storage/filesystem_test.rb +26 -3
  105. data/test/storage/fog_test.rb +181 -3
  106. data/test/storage/s3_test.rb +239 -4
  107. data/test/style_test.rb +18 -14
  108. data/test/tempfile_factory_test.rb +13 -0
  109. data/test/thumbnail_test.rb +96 -16
  110. data/test/validators/attachment_content_type_validator_test.rb +181 -55
  111. data/test/validators/attachment_size_validator_test.rb +10 -0
  112. data/test/validators_test.rb +8 -1
  113. metadata +126 -92
  114. data/Gemfile.lock +0 -157
  115. data/features/support/fixtures/.boot_config.rb.swo +0 -0
  116. data/images.rake +0 -21
  117. data/lib/.DS_Store +0 -0
  118. data/lib/paperclip/.DS_Store +0 -0
  119. data/lib/paperclip/attachment_options.rb +0 -9
  120. data/lib/paperclip/instance_methods.rb +0 -35
  121. data/test/attachment_options_test.rb +0 -27
@@ -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
- assert !File.exists?(@thumb_path)
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
- assert File.exists?(@thumb_path)
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
- assert !File.exists?(@thumb_small_path)
130
- assert !File.exists?(@thumb_large_path)
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
- assert File.exists?(@thumb_small_path)
135
- assert File.exists?(@thumb_large_path)
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
- assert !File.exists?(@thumb_small_path)
140
- assert !File.exists?(@thumb_large_path)
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
- assert File.exists?(@thumb_small_path)
144
- assert !File.exists?(@thumb_large_path)
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
- assert File.exists?(@thumb_large_path)
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
- assert File.exists?(@dummy.avatar.path(:large))
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
- assert ! File.exists?(@saved_path)
195
+ assert_file_not_exists(@saved_path)
196
196
  end
197
197
 
198
198
  should "not have its next two parent directories" do
199
- assert ! File.exists?(File.dirname(@saved_path))
200
- assert ! File.exists?(File.dirname(File.dirname(@saved_path)))
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
- context "A model with no convert_options setting" do
211
- setup do
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 :styles => { :large => "300x300>",
228
- :medium => "100x100",
229
- :thumb => ["32x32#", :gif] },
230
- :convert_options => "-strip -depth 8",
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
- should "have its definition return nil when asked about source_file_options" do
254
- assert ! Dummy.attachment_definitions[:avatar][:source_file_options]
255
- end
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 "have its definition return source_file_options value when asked about source_file_options" do
269
- assert_equal "-density 400", Dummy.attachment_definitions[:avatar][:source_file_options]
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
- [000,002,022].each do |umask|
275
- context "when the umask is #{umask}" do
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 umask" do
244
+ should "respect the current perms" do
289
245
  @dummy.avatar = @file
290
246
  @dummy.save
291
- assert_equal 0666&~umask, 0666&File.stat(@dummy.avatar.path).mode
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
- assert File.exists?(p)
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
- assert ! File.exists?(p)
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
- assert ! File.exists?(p)
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 @d2.valid?, @d2.errors.full_messages.inspect
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
- assert File.exists?(@dummy.avatar.path(:original))
461
- assert File.exists?(@dummy.avatar.path(:thumb))
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
- @dummy.avatar.reprocess! 'mini'
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
- assert File.exists?(@dummy.avatar.path(:original))
473
- assert File.exists?(@dummy.avatar.path(:thumb))
474
- assert File.exists?(@dummy.avatar.path(:mini))
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
@@ -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
- def teardown
16
- @file.close
17
- end
10
+ context "for an attachment" do
11
+ setup do
12
+ @file = File.new(fixture_file("5k.png"))
13
+ @file.binmode
18
14
 
19
- should "get the right filename" do
20
- assert_equal "5k.png", @subject.original_filename
21
- end
15
+ @attachment.assign(@file)
16
+ @attachment.save
17
+ @subject = Paperclip.io_adapters.for(@attachment)
18
+ end
22
19
 
23
- should "force binmode on tempfile" do
24
- assert @subject.instance_variable_get("@tempfile").binmode?
25
- end
20
+ teardown do
21
+ @file.close
22
+ end
26
23
 
27
- should "get the content type" do
28
- assert_equal "image/png", @subject.content_type
29
- end
24
+ should "get the right filename" do
25
+ assert_equal "5k.png", @subject.original_filename
26
+ end
30
27
 
31
- should "get the file's size" do
32
- assert_equal 4456, @subject.size
33
- end
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
- should "generate a MD5 hash of the contents" do
40
- expected = Digest::MD5.file(@file.path).to_s
41
- assert_equal expected, @subject.fingerprint
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
- should "read the contents of the file" do
45
- expected = @file.read
46
- actual = @subject.read
47
- assert expected.length > 0
48
- assert_equal expected.length, actual.length
49
- assert_equal expected, actual
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