paperclip 3.5.4 → 4.3.7

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 (198) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -6
  3. data/.hound.yml +1066 -0
  4. data/.rubocop.yml +1 -0
  5. data/.travis.yml +11 -17
  6. data/Appraisals +6 -14
  7. data/CONTRIBUTING.md +13 -8
  8. data/Gemfile +16 -3
  9. data/LICENSE +1 -3
  10. data/NEWS +167 -49
  11. data/README.md +294 -75
  12. data/RELEASING.md +17 -0
  13. data/Rakefile +6 -8
  14. data/features/basic_integration.feature +24 -6
  15. data/features/step_definitions/attachment_steps.rb +30 -22
  16. data/features/step_definitions/html_steps.rb +2 -2
  17. data/features/step_definitions/rails_steps.rb +44 -14
  18. data/features/step_definitions/web_steps.rb +1 -103
  19. data/features/support/env.rb +2 -2
  20. data/features/support/file_helpers.rb +2 -2
  21. data/features/support/fixtures/gemfile.txt +1 -1
  22. data/features/support/rails.rb +2 -1
  23. data/gemfiles/3.2.gemfile +14 -6
  24. data/gemfiles/4.1.gemfile +19 -0
  25. data/gemfiles/4.2.gemfile +19 -0
  26. data/lib/generators/paperclip/paperclip_generator.rb +0 -2
  27. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +1 -1
  28. data/lib/paperclip/attachment.rb +132 -38
  29. data/lib/paperclip/attachment_registry.rb +1 -1
  30. data/lib/paperclip/callbacks.rb +11 -1
  31. data/lib/paperclip/content_type_detector.rb +25 -22
  32. data/lib/paperclip/deprecations.rb +42 -0
  33. data/lib/paperclip/errors.rb +5 -0
  34. data/lib/paperclip/file_command_content_type_detector.rb +6 -8
  35. data/lib/paperclip/geometry_detector_factory.rb +3 -1
  36. data/lib/paperclip/geometry_parser_factory.rb +1 -1
  37. data/lib/paperclip/has_attached_file.rb +10 -0
  38. data/lib/paperclip/interpolations/plural_cache.rb +6 -5
  39. data/lib/paperclip/interpolations.rb +25 -12
  40. data/lib/paperclip/io_adapters/abstract_adapter.rb +3 -1
  41. data/lib/paperclip/io_adapters/attachment_adapter.rb +4 -4
  42. data/lib/paperclip/io_adapters/data_uri_adapter.rb +5 -10
  43. data/lib/paperclip/io_adapters/stringio_adapter.rb +6 -10
  44. data/lib/paperclip/io_adapters/uri_adapter.rb +30 -11
  45. data/lib/paperclip/locales/de.yml +18 -0
  46. data/lib/paperclip/locales/en.yml +1 -0
  47. data/lib/paperclip/locales/es.yml +18 -0
  48. data/lib/paperclip/locales/ja.yml +18 -0
  49. data/lib/paperclip/locales/pt-BR.yml +18 -0
  50. data/lib/paperclip/locales/zh-CN.yml +18 -0
  51. data/lib/paperclip/locales/zh-HK.yml +18 -0
  52. data/lib/paperclip/locales/zh-TW.yml +18 -0
  53. data/lib/paperclip/matchers/have_attached_file_matcher.rb +2 -1
  54. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +2 -1
  55. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +2 -1
  56. data/lib/paperclip/media_type_spoof_detector.rb +89 -0
  57. data/lib/paperclip/processor.rb +0 -37
  58. data/lib/paperclip/processor_helpers.rb +50 -0
  59. data/lib/paperclip/rails_environment.rb +25 -0
  60. data/lib/paperclip/schema.rb +10 -2
  61. data/lib/paperclip/storage/filesystem.rb +1 -1
  62. data/lib/paperclip/storage/fog.rb +18 -7
  63. data/lib/paperclip/storage/s3.rb +53 -22
  64. data/lib/paperclip/style.rb +8 -2
  65. data/lib/paperclip/tempfile_factory.rb +5 -1
  66. data/lib/paperclip/thumbnail.rb +12 -10
  67. data/lib/paperclip/url_generator.rb +11 -3
  68. data/lib/paperclip/validators/attachment_content_type_validator.rb +4 -0
  69. data/lib/paperclip/validators/attachment_file_name_validator.rb +80 -0
  70. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +29 -0
  71. data/lib/paperclip/validators/attachment_presence_validator.rb +4 -0
  72. data/lib/paperclip/validators/attachment_size_validator.rb +11 -3
  73. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +27 -0
  74. data/lib/paperclip/validators.rb +10 -3
  75. data/lib/paperclip/version.rb +1 -1
  76. data/lib/paperclip.rb +26 -8
  77. data/lib/tasks/paperclip.rake +17 -2
  78. data/paperclip.gemspec +16 -14
  79. data/shoulda_macros/paperclip.rb +0 -1
  80. data/spec/paperclip/attachment_definitions_spec.rb +13 -0
  81. data/{test/attachment_processing_test.rb → spec/paperclip/attachment_processing_spec.rb} +20 -21
  82. data/spec/paperclip/attachment_registry_spec.rb +130 -0
  83. data/{test/attachment_test.rb → spec/paperclip/attachment_spec.rb} +438 -397
  84. data/{test/content_type_detector_test.rb → spec/paperclip/content_type_detector_spec.rb} +16 -19
  85. data/spec/paperclip/deprecations_spec.rb +65 -0
  86. data/{test/file_command_content_type_detector_test.rb → spec/paperclip/file_command_content_type_detector_spec.rb} +5 -6
  87. data/spec/paperclip/filename_cleaner_spec.rb +14 -0
  88. data/spec/paperclip/geometry_detector_spec.rb +39 -0
  89. data/{test/geometry_parser_test.rb → spec/paperclip/geometry_parser_spec.rb} +27 -27
  90. data/{test/geometry_test.rb → spec/paperclip/geometry_spec.rb} +50 -52
  91. data/spec/paperclip/glue_spec.rb +44 -0
  92. data/{test/has_attached_file_test.rb → spec/paperclip/has_attached_file_spec.rb} +45 -28
  93. data/{test/integration_test.rb → spec/paperclip/integration_spec.rb} +134 -126
  94. data/{test/interpolations_test.rb → spec/paperclip/interpolations_spec.rb} +70 -46
  95. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +78 -0
  96. data/{test/io_adapters/attachment_adapter_test.rb → spec/paperclip/io_adapters/attachment_adapter_spec.rb} +27 -29
  97. data/{test/io_adapters/data_uri_adapter_test.rb → spec/paperclip/io_adapters/data_uri_adapter_spec.rb} +26 -17
  98. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
  99. data/{test/io_adapters/file_adapter_test.rb → spec/paperclip/io_adapters/file_adapter_spec.rb} +36 -40
  100. data/{test/io_adapters/http_url_proxy_adapter_test.rb → spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb} +31 -29
  101. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
  102. data/{test/io_adapters/nil_adapter_test.rb → spec/paperclip/io_adapters/nil_adapter_spec.rb} +7 -7
  103. data/{test/io_adapters/registry_test.rb → spec/paperclip/io_adapters/registry_spec.rb} +10 -7
  104. data/{test/io_adapters/stringio_adapter_test.rb → spec/paperclip/io_adapters/stringio_adapter_spec.rb} +20 -17
  105. data/{test/io_adapters/uploaded_file_adapter_test.rb → spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb} +41 -41
  106. data/{test/io_adapters/uri_adapter_test.rb → spec/paperclip/io_adapters/uri_adapter_spec.rb} +53 -28
  107. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
  108. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +99 -0
  109. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
  110. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
  111. data/spec/paperclip/media_type_spoof_detector_spec.rb +79 -0
  112. data/spec/paperclip/meta_class_spec.rb +30 -0
  113. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +84 -0
  114. data/{test/paperclip_test.rb → spec/paperclip/paperclip_spec.rb} +53 -48
  115. data/spec/paperclip/plural_cache_spec.rb +37 -0
  116. data/spec/paperclip/processor_helpers_spec.rb +57 -0
  117. data/{test/processor_test.rb → spec/paperclip/processor_spec.rb} +5 -5
  118. data/spec/paperclip/rails_environment_spec.rb +33 -0
  119. data/{test/rake_test.rb → spec/paperclip/rake_spec.rb} +15 -15
  120. data/spec/paperclip/schema_spec.rb +248 -0
  121. data/{test/storage/filesystem_test.rb → spec/paperclip/storage/filesystem_spec.rb} +18 -18
  122. data/spec/paperclip/storage/fog_spec.rb +535 -0
  123. data/spec/paperclip/storage/s3_live_spec.rb +182 -0
  124. data/spec/paperclip/storage/s3_spec.rb +1526 -0
  125. data/spec/paperclip/style_spec.rb +255 -0
  126. data/spec/paperclip/tempfile_factory_spec.rb +33 -0
  127. data/{test/thumbnail_test.rb → spec/paperclip/thumbnail_spec.rb} +123 -107
  128. data/spec/paperclip/url_generator_spec.rb +211 -0
  129. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
  130. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +160 -0
  131. data/{test/validators/attachment_presence_validator_test.rb → spec/paperclip/validators/attachment_presence_validator_spec.rb} +20 -20
  132. data/{test/validators/attachment_size_validator_test.rb → spec/paperclip/validators/attachment_size_validator_spec.rb} +65 -58
  133. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +52 -0
  134. data/spec/paperclip/validators_spec.rb +164 -0
  135. data/spec/spec_helper.rb +43 -0
  136. data/spec/support/assertions.rb +71 -0
  137. data/spec/support/deprecations.rb +9 -0
  138. data/spec/support/fake_model.rb +25 -0
  139. data/spec/support/fake_rails.rb +12 -0
  140. data/spec/support/fixtures/empty.html +1 -0
  141. data/spec/support/fixtures/empty.xlsx +0 -0
  142. data/spec/support/fixtures/spaced file.jpg +0 -0
  143. data/spec/support/matchers/accept.rb +5 -0
  144. data/spec/support/matchers/exist.rb +5 -0
  145. data/spec/support/matchers/have_column.rb +23 -0
  146. data/spec/support/model_reconstruction.rb +60 -0
  147. data/spec/support/rails_helpers.rb +7 -0
  148. data/spec/support/test_data.rb +13 -0
  149. data/spec/support/version_helper.rb +9 -0
  150. metadata +334 -219
  151. data/RUNNING_TESTS.md +0 -4
  152. data/gemfiles/3.0.gemfile +0 -11
  153. data/gemfiles/3.1.gemfile +0 -11
  154. data/gemfiles/4.0.gemfile +0 -11
  155. data/test/attachment_definitions_test.rb +0 -12
  156. data/test/attachment_registry_test.rb +0 -88
  157. data/test/filename_cleaner_test.rb +0 -14
  158. data/test/generator_test.rb +0 -84
  159. data/test/geometry_detector_test.rb +0 -24
  160. data/test/helper.rb +0 -232
  161. data/test/io_adapters/abstract_adapter_test.rb +0 -58
  162. data/test/io_adapters/empty_string_adapter_test.rb +0 -18
  163. data/test/io_adapters/identity_adapter_test.rb +0 -8
  164. data/test/matchers/have_attached_file_matcher_test.rb +0 -24
  165. data/test/matchers/validate_attachment_content_type_matcher_test.rb +0 -110
  166. data/test/matchers/validate_attachment_presence_matcher_test.rb +0 -69
  167. data/test/matchers/validate_attachment_size_matcher_test.rb +0 -86
  168. data/test/meta_class_test.rb +0 -32
  169. data/test/paperclip_missing_attachment_styles_test.rb +0 -90
  170. data/test/plural_cache_test.rb +0 -36
  171. data/test/schema_test.rb +0 -200
  172. data/test/storage/fog_test.rb +0 -473
  173. data/test/storage/s3_live_test.rb +0 -179
  174. data/test/storage/s3_test.rb +0 -1356
  175. data/test/style_test.rb +0 -213
  176. data/test/support/mock_model.rb +0 -2
  177. data/test/tempfile_factory_test.rb +0 -17
  178. data/test/url_generator_test.rb +0 -187
  179. data/test/validators/attachment_content_type_validator_test.rb +0 -324
  180. data/test/validators_test.rb +0 -61
  181. /data/{test → spec}/database.yml +0 -0
  182. /data/{test → spec/support}/fixtures/12k.png +0 -0
  183. /data/{test → spec/support}/fixtures/50x50.png +0 -0
  184. /data/{test → spec/support}/fixtures/5k.png +0 -0
  185. /data/{test → spec/support}/fixtures/animated +0 -0
  186. /data/{test → spec/support}/fixtures/animated.gif +0 -0
  187. /data/{test → spec/support}/fixtures/animated.unknown +0 -0
  188. /data/{test → spec/support}/fixtures/bad.png +0 -0
  189. /data/{test → spec/support}/fixtures/fog.yml +0 -0
  190. /data/{test → spec/support}/fixtures/rotated.jpg +0 -0
  191. /data/{test → spec/support}/fixtures/s3.yml +0 -0
  192. /data/{test → spec/support}/fixtures/spaced file.png +0 -0
  193. /data/{test → spec/support}/fixtures/text.txt +0 -0
  194. /data/{test → spec/support}/fixtures/twopage.pdf +0 -0
  195. /data/{test → spec/support}/fixtures/uppercase.PNG +0 -0
  196. /data/{test → spec}/support/mock_attachment.rb +0 -0
  197. /data/{test → spec}/support/mock_interpolator.rb +0 -0
  198. /data/{test → spec}/support/mock_url_generator_builder.rb +0 -0
@@ -1,54 +1,62 @@
1
- require './test/helper'
1
+ require 'spec_helper'
2
+
3
+ describe Paperclip::UriAdapter do
4
+ let(:content_type) { "image/png" }
5
+ let(:meta) { {} }
6
+
7
+ before do
8
+ @open_return = StringIO.new("xxx")
9
+ @open_return.stubs(:content_type).returns(content_type)
10
+ @open_return.stubs(:meta).returns(meta)
11
+ Paperclip::UriAdapter.any_instance.
12
+ stubs(:download_content).returns(@open_return)
13
+ end
2
14
 
3
- class UriProxyTest < Test::Unit::TestCase
4
15
  context "a new instance" do
5
- setup do
6
- @open_return = StringIO.new("xxx")
7
- @open_return.stubs(:content_type).returns("image/png")
8
- Paperclip::UriAdapter.any_instance.stubs(:download_content).returns(@open_return)
16
+ before do
9
17
  @uri = URI.parse("http://thoughtbot.com/images/thoughtbot-logo.png")
10
18
  @subject = Paperclip.io_adapters.for(@uri)
11
19
  end
12
20
 
13
- should "return a file name" do
21
+ it "returns a file name" do
14
22
  assert_equal "thoughtbot-logo.png", @subject.original_filename
15
23
  end
16
24
 
17
- should 'close open handle after reading' do
25
+ it 'closes open handle after reading' do
18
26
  assert_equal true, @open_return.closed?
19
27
  end
20
28
 
21
- should "return a content type" do
29
+ it "returns a content type" do
22
30
  assert_equal "image/png", @subject.content_type
23
31
  end
24
32
 
25
- should "return the size of the data" do
33
+ it "returns the size of the data" do
26
34
  assert_equal @open_return.size, @subject.size
27
35
  end
28
36
 
29
- should "generate an MD5 hash of the contents" do
37
+ it "generates an MD5 hash of the contents" do
30
38
  assert_equal Digest::MD5.hexdigest("xxx"), @subject.fingerprint
31
39
  end
32
40
 
33
- should "generate correct fingerprint after read" do
41
+ it "generates correct fingerprint after read" do
34
42
  fingerprint = Digest::MD5.hexdigest(@subject.read)
35
43
  assert_equal fingerprint, @subject.fingerprint
36
44
  end
37
45
 
38
- should "generate same fingerprint" do
46
+ it "generates same fingerprint" do
39
47
  assert_equal @subject.fingerprint, @subject.fingerprint
40
48
  end
41
49
 
42
- should "return the data contained in the StringIO" do
50
+ it "returns the data contained in the StringIO" do
43
51
  assert_equal "xxx", @subject.read
44
52
  end
45
53
 
46
- should 'accept a content_type' do
54
+ it 'accepts a content_type' do
47
55
  @subject.content_type = 'image/png'
48
56
  assert_equal 'image/png', @subject.content_type
49
57
  end
50
58
 
51
- should 'accept an orgiginal_filename' do
59
+ it 'accepts an orgiginal_filename' do
52
60
  @subject.original_filename = 'image.png'
53
61
  assert_equal 'image.png', @subject.original_filename
54
62
  end
@@ -56,46 +64,63 @@ class UriProxyTest < Test::Unit::TestCase
56
64
  end
57
65
 
58
66
  context "a directory index url" do
59
- setup do
60
- Paperclip::UriAdapter.any_instance.stubs(:download_content).returns(StringIO.new("xxx"))
67
+ let(:content_type) { "text/html" }
68
+
69
+ before do
61
70
  @uri = URI.parse("http://thoughtbot.com")
62
71
  @subject = Paperclip.io_adapters.for(@uri)
63
72
  end
64
73
 
65
- should "return a file name" do
74
+ it "returns a file name" do
66
75
  assert_equal "index.html", @subject.original_filename
67
76
  end
68
77
 
69
- should "return a content type" do
78
+ it "returns a content type" do
70
79
  assert_equal "text/html", @subject.content_type
71
80
  end
72
81
  end
73
82
 
74
83
  context "a url with query params" do
75
- setup do
76
- Paperclip::UriAdapter.any_instance.stubs(:download_content).returns(StringIO.new("xxx"))
84
+ before do
77
85
  @uri = URI.parse("https://github.com/thoughtbot/paperclip?file=test")
78
86
  @subject = Paperclip.io_adapters.for(@uri)
79
87
  end
80
88
 
81
- should "return a file name" do
89
+ it "returns a file name" do
82
90
  assert_equal "paperclip", @subject.original_filename
83
91
  end
84
92
  end
85
93
 
94
+ context "a url with content disposition headers" do
95
+ let(:file_name) { "test_document.pdf" }
96
+ let(:meta) do
97
+ {
98
+ "content-disposition" => "attachment; filename=\"#{file_name}\";",
99
+ }
100
+ end
101
+
102
+ before do
103
+ @uri = URI.parse("https://github.com/thoughtbot/paperclip?file=test")
104
+ @subject = Paperclip.io_adapters.for(@uri)
105
+ end
106
+
107
+ it "returns a file name" do
108
+ assert_equal file_name, @subject.original_filename
109
+ end
110
+ end
111
+
86
112
  context "a url with restricted characters in the filename" do
87
- setup do
88
- Paperclip::UriAdapter.any_instance.stubs(:download_content).returns(StringIO.new("xxx"))
113
+ before do
89
114
  @uri = URI.parse("https://github.com/thoughtbot/paper:clip.jpg")
90
115
  @subject = Paperclip.io_adapters.for(@uri)
91
116
  end
92
117
 
93
- should "not generate filenames that include restricted characters" do
118
+ it "does not generate filenames that include restricted characters" do
94
119
  assert_equal "paper_clip.jpg", @subject.original_filename
95
120
  end
96
121
 
97
- should "not generate paths that include restricted characters" do
98
- assert_no_match /:/, @subject.path
122
+ it "does not generate paths that include restricted characters" do
123
+ expect(@subject.path).to_not match(/:/)
99
124
  end
100
125
  end
101
126
 
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ require 'paperclip/matchers'
3
+
4
+ describe Paperclip::Shoulda::Matchers::HaveAttachedFileMatcher do
5
+ extend Paperclip::Shoulda::Matchers
6
+
7
+ it "rejects the dummy class if it has no attachment" do
8
+ reset_table "dummies"
9
+ reset_class "Dummy"
10
+ matcher = self.class.have_attached_file(:avatar)
11
+ expect(matcher).to_not accept(Dummy)
12
+ end
13
+
14
+ it 'accepts the dummy class if it has an attachment' do
15
+ rebuild_model
16
+ matcher = self.class.have_attached_file(:avatar)
17
+ expect(matcher).to accept(Dummy)
18
+ end
19
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+ require 'paperclip/matchers'
3
+
4
+ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
5
+ extend Paperclip::Shoulda::Matchers
6
+
7
+ before do
8
+ reset_table("dummies") do |d|
9
+ d.string :title
10
+ d.string :avatar_file_name
11
+ d.string :avatar_content_type
12
+ end
13
+ reset_class "Dummy"
14
+ Dummy.do_not_validate_attachment_file_type :avatar
15
+ Dummy.has_attached_file :avatar
16
+ end
17
+
18
+ it "rejects a class with no validation" do
19
+ expect(matcher).to_not accept(Dummy)
20
+ end
21
+
22
+ it 'rejects a class when the validation fails' do
23
+ Dummy.validates_attachment_content_type :avatar, content_type: %r{audio/.*}
24
+ expect(matcher).to_not accept(Dummy)
25
+ end
26
+
27
+ it "accepts a class with a matching validation" do
28
+ Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
29
+ expect(matcher).to accept(Dummy)
30
+ end
31
+
32
+ it "accepts a class with other validations but matching types" do
33
+ Dummy.validates_presence_of :title
34
+ Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
35
+ expect(matcher).to accept(Dummy)
36
+ end
37
+
38
+ it "accepts a class that matches and a matcher that only specifies 'allowing'" do
39
+ Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
40
+ matcher = plain_matcher.allowing(%w(image/png image/jpeg))
41
+
42
+ expect(matcher).to accept(Dummy)
43
+ end
44
+
45
+ it "rejects a class that does not match and a matcher that only specifies 'allowing'" do
46
+ Dummy.validates_attachment_content_type :avatar, content_type: %r{audio/.*}
47
+ matcher = plain_matcher.allowing(%w(image/png image/jpeg))
48
+
49
+ expect(matcher).to_not accept(Dummy)
50
+ end
51
+
52
+ it "accepts a class that matches and a matcher that only specifies 'rejecting'" do
53
+ Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
54
+ matcher = plain_matcher.rejecting(%w(audio/mp3 application/octet-stream))
55
+
56
+ expect(matcher).to accept(Dummy)
57
+ end
58
+
59
+ it "rejects a class that does not match and a matcher that only specifies 'rejecting'" do
60
+ Dummy.validates_attachment_content_type :avatar, content_type: %r{audio/.*}
61
+ matcher = plain_matcher.rejecting(%w(audio/mp3 application/octet-stream))
62
+
63
+ expect(matcher).to_not accept(Dummy)
64
+ end
65
+
66
+ context "using an :if to control the validation" do
67
+ before do
68
+ Dummy.class_eval do
69
+ validates_attachment_content_type :avatar, content_type: %r{image/*} , if: :go
70
+ attr_accessor :go
71
+ end
72
+ end
73
+
74
+ it "runs the validation if the control is true" do
75
+ dummy = Dummy.new
76
+ dummy.go = true
77
+ expect(matcher).to accept(dummy)
78
+ end
79
+
80
+ it "does not run the validation if the control is false" do
81
+ dummy = Dummy.new
82
+ dummy.go = false
83
+ expect(matcher).to_not accept(dummy)
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def plain_matcher
90
+ self.class.validate_attachment_content_type(:avatar)
91
+ end
92
+
93
+ def matcher
94
+ plain_matcher.
95
+ allowing(%w(image/png image/jpeg)).
96
+ rejecting(%w(audio/mp3 application/octet-stream))
97
+ end
98
+
99
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+ require 'paperclip/matchers'
3
+
4
+ describe Paperclip::Shoulda::Matchers::ValidateAttachmentPresenceMatcher do
5
+ extend Paperclip::Shoulda::Matchers
6
+
7
+ before do
8
+ reset_table("dummies") do |d|
9
+ d.string :avatar_file_name
10
+ end
11
+ reset_class "Dummy"
12
+ Dummy.has_attached_file :avatar
13
+ Dummy.do_not_validate_attachment_file_type :avatar
14
+ end
15
+
16
+ it "rejects a class with no validation" do
17
+ expect(matcher).to_not accept(Dummy)
18
+ end
19
+
20
+ it "accepts a class with a matching validation" do
21
+ Dummy.validates_attachment_presence :avatar
22
+ expect(matcher).to accept(Dummy)
23
+ end
24
+
25
+ it "accepts an instance with other attachment validations" do
26
+ reset_table("dummies") do |d|
27
+ d.string :avatar_file_name
28
+ d.string :avatar_content_type
29
+ end
30
+ Dummy.class_eval do
31
+ validates_attachment_presence :avatar
32
+ validates_attachment_content_type :avatar, content_type: 'image/gif'
33
+ end
34
+ dummy = Dummy.new
35
+
36
+ dummy.avatar = File.new fixture_file('5k.png')
37
+
38
+ expect(matcher).to accept(dummy)
39
+ end
40
+
41
+ context "using an :if to control the validation" do
42
+ before do
43
+ Dummy.class_eval do
44
+ validates_attachment_presence :avatar, if: :go
45
+ attr_accessor :go
46
+ end
47
+ end
48
+
49
+ it "runs the validation if the control is true" do
50
+ dummy = Dummy.new
51
+ dummy.avatar = nil
52
+ dummy.go = true
53
+ expect(matcher).to accept(dummy)
54
+ end
55
+
56
+ it "does not run the validation if the control is false" do
57
+ dummy = Dummy.new
58
+ dummy.avatar = nil
59
+ dummy.go = false
60
+ expect(matcher).to_not accept(dummy)
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def matcher
67
+ self.class.validate_attachment_presence(:avatar)
68
+ end
69
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+ require 'paperclip/matchers'
3
+
4
+ describe Paperclip::Shoulda::Matchers::ValidateAttachmentSizeMatcher do
5
+ extend Paperclip::Shoulda::Matchers
6
+
7
+ before do
8
+ reset_table("dummies") do |d|
9
+ d.string :avatar_file_name
10
+ d.integer :avatar_file_size
11
+ end
12
+ reset_class "Dummy"
13
+ Dummy.do_not_validate_attachment_file_type :avatar
14
+ Dummy.has_attached_file :avatar
15
+ end
16
+
17
+ context "Limiting size" do
18
+ it "rejects a class with no validation" do
19
+ expect(matcher.in(256..1024)).to_not accept(Dummy)
20
+ end
21
+
22
+ it "rejects a class with a validation that's too high" do
23
+ Dummy.validates_attachment_size :avatar, in: 256..2048
24
+ expect(matcher.in(256..1024)).to_not accept(Dummy)
25
+ end
26
+
27
+ it "accepts a class with a validation that's too low" do
28
+ Dummy.validates_attachment_size :avatar, in: 0..1024
29
+ expect(matcher.in(256..1024)).to_not accept(Dummy)
30
+ end
31
+
32
+ it "accepts a class with a validation that matches" do
33
+ Dummy.validates_attachment_size :avatar, in: 256..1024
34
+ expect(matcher.in(256..1024)).to accept(Dummy)
35
+ end
36
+ end
37
+
38
+ context "allowing anything" do
39
+ it "given a class with an upper limit" do
40
+ Dummy.validates_attachment_size :avatar, less_than: 1
41
+ expect(matcher).to accept(Dummy)
42
+ end
43
+
44
+ it "given a class with a lower limit" do
45
+ Dummy.validates_attachment_size :avatar, greater_than: 1
46
+ expect(matcher).to accept(Dummy)
47
+ end
48
+ end
49
+
50
+ context "using an :if to control the validation" do
51
+ before do
52
+ Dummy.class_eval do
53
+ validates_attachment_size :avatar, greater_than: 1024, if: :go
54
+ attr_accessor :go
55
+ end
56
+ end
57
+
58
+ it "run the validation if the control is true" do
59
+ dummy = Dummy.new
60
+ dummy.go = true
61
+ expect(matcher.greater_than(1024)).to accept(dummy)
62
+ end
63
+
64
+ it "not run the validation if the control is false" do
65
+ dummy = Dummy.new
66
+ dummy.go = false
67
+ expect(matcher.greater_than(1024)).to_not accept(dummy)
68
+ end
69
+ end
70
+
71
+ context "post processing" do
72
+ before do
73
+ Dummy.validates_attachment_size :avatar, greater_than: 1024
74
+ end
75
+
76
+ it "be skipped" do
77
+ dummy = Dummy.new
78
+ dummy.avatar.expects(:post_process).never
79
+ expect(matcher.greater_than(1024)).to accept(dummy)
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def matcher
86
+ self.class.validate_attachment_size(:avatar)
87
+ end
88
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Paperclip::MediaTypeSpoofDetector do
4
+ it 'rejects a file that is named .html and identifies as PNG' do
5
+ file = File.open(fixture_file("5k.png"))
6
+ assert Paperclip::MediaTypeSpoofDetector.using(file, "5k.html", "image/png").spoofed?
7
+ end
8
+
9
+ it 'does not reject a file that is named .jpg and identifies as PNG' do
10
+ file = File.open(fixture_file("5k.png"))
11
+ assert ! Paperclip::MediaTypeSpoofDetector.using(file, "5k.jpg", "image/png").spoofed?
12
+ end
13
+
14
+ it 'does not reject a file that is named .html and identifies as HTML' do
15
+ file = File.open(fixture_file("empty.html"))
16
+ assert ! Paperclip::MediaTypeSpoofDetector.using(file, "empty.html", "text/html").spoofed?
17
+ end
18
+
19
+ it 'does not reject a file that does not have a name' do
20
+ file = File.open(fixture_file("empty.html"))
21
+ assert ! Paperclip::MediaTypeSpoofDetector.using(file, "", "text/html").spoofed?
22
+ end
23
+
24
+ it 'does not reject a file that does have an extension' do
25
+ file = File.open(fixture_file("empty.html"))
26
+ assert ! Paperclip::MediaTypeSpoofDetector.using(file, "data", "text/html").spoofed?
27
+ end
28
+
29
+ it 'does not reject when the supplied file is an IOAdapter' do
30
+ adapter = Paperclip.io_adapters.for(File.new(fixture_file("5k.png")))
31
+ assert ! Paperclip::MediaTypeSpoofDetector.using(adapter, adapter.original_filename, adapter.content_type).spoofed?
32
+ end
33
+
34
+ it 'does not reject when the extension => content_type is in :content_type_mappings' do
35
+ begin
36
+ Paperclip.options[:content_type_mappings] = { pem: "text/plain" }
37
+ file = Tempfile.open(["test", ".PEM"])
38
+ file.puts "Certificate!"
39
+ file.close
40
+ adapter = Paperclip.io_adapters.for(File.new(file.path));
41
+ assert ! Paperclip::MediaTypeSpoofDetector.using(adapter, adapter.original_filename, adapter.content_type).spoofed?
42
+ ensure
43
+ Paperclip.options[:content_type_mappings] = {}
44
+ end
45
+ end
46
+
47
+ context "file named .html and is as HTML, but we're told JPG" do
48
+ let(:file) { File.open(fixture_file("empty.html")) }
49
+ let(:spoofed?) { Paperclip::MediaTypeSpoofDetector.using(file, "empty.html", "image/jpg").spoofed? }
50
+
51
+ it "rejects the file" do
52
+ assert spoofed?
53
+ end
54
+
55
+ it "logs info about the detected spoof" do
56
+ Paperclip.expects(:log).with('Content Type Spoof: Filename empty.html (image/jpg from Headers, ["text/html"] from Extension), content type discovered from file command: text/html. See documentation to allow this combination.')
57
+ spoofed?
58
+ end
59
+ end
60
+
61
+ it "does not reject if content_type is empty but otherwise checks out" do
62
+ file = File.open(fixture_file("empty.html"))
63
+ assert ! Paperclip::MediaTypeSpoofDetector.using(file, "empty.html", "").spoofed?
64
+ end
65
+
66
+ it 'does allow array as :content_type_mappings' do
67
+ begin
68
+ Paperclip.options[:content_type_mappings] = {
69
+ html: ['binary', 'text/html']
70
+ }
71
+ file = File.open(fixture_file('empty.html'))
72
+ spoofed = Paperclip::MediaTypeSpoofDetector
73
+ .using(file, "empty.html", "text/html").spoofed?
74
+ assert !spoofed
75
+ ensure
76
+ Paperclip.options[:content_type_mappings] = {}
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Metaclasses' do
4
+ context "A meta-class of dummy" do
5
+ if active_support_version >= "4.1" || ruby_version < "2.1"
6
+ before do
7
+ rebuild_model
8
+ reset_class("Dummy")
9
+ end
10
+
11
+ it "is able to use Paperclip like a normal class" do
12
+ @dummy = Dummy.new
13
+
14
+ assert_nothing_raised do
15
+ rebuild_meta_class_of(@dummy)
16
+ end
17
+ end
18
+
19
+ it "works like any other instance" do
20
+ @dummy = Dummy.new
21
+ rebuild_meta_class_of(@dummy)
22
+
23
+ assert_nothing_raised do
24
+ @dummy.avatar = File.new(fixture_file("5k.png"), 'rb')
25
+ end
26
+ assert @dummy.save
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Missing Attachment Styles' do
4
+ before do
5
+ Paperclip::AttachmentRegistry.clear
6
+ end
7
+
8
+ after do
9
+ File.unlink(Paperclip.registered_attachments_styles_path) rescue nil
10
+ end
11
+
12
+ it "enables to get and set path to registered styles file" do
13
+ assert_equal ROOT.join('tmp/public/system/paperclip_attachments.yml').to_s, Paperclip.registered_attachments_styles_path
14
+ Paperclip.registered_attachments_styles_path = '/tmp/config/paperclip_attachments.yml'
15
+ assert_equal '/tmp/config/paperclip_attachments.yml', Paperclip.registered_attachments_styles_path
16
+ Paperclip.registered_attachments_styles_path = nil
17
+ assert_equal ROOT.join('tmp/public/system/paperclip_attachments.yml').to_s, Paperclip.registered_attachments_styles_path
18
+ end
19
+
20
+ it "is able to get current attachment styles" do
21
+ assert_equal Hash.new, Paperclip.send(:current_attachments_styles)
22
+ rebuild_model styles: {croppable: '600x600>', big: '1000x1000>'}
23
+ expected_hash = { Dummy: {avatar: [:big, :croppable]}}
24
+ assert_equal expected_hash, Paperclip.send(:current_attachments_styles)
25
+ end
26
+
27
+ it "is able to save current attachment styles for further comparison" do
28
+ rebuild_model styles: {croppable: '600x600>', big: '1000x1000>'}
29
+ Paperclip.save_current_attachments_styles!
30
+ expected_hash = { Dummy: {avatar: [:big, :croppable]}}
31
+ assert_equal expected_hash, YAML.load_file(Paperclip.registered_attachments_styles_path)
32
+ end
33
+
34
+ it "is able to read registered attachment styles from file" do
35
+ rebuild_model styles: {croppable: '600x600>', big: '1000x1000>'}
36
+ Paperclip.save_current_attachments_styles!
37
+ expected_hash = { Dummy: {avatar: [:big, :croppable]}}
38
+ assert_equal expected_hash, Paperclip.send(:get_registered_attachments_styles)
39
+ end
40
+
41
+ it "is able to calculate differences between registered styles and current styles" do
42
+ rebuild_model styles: {croppable: '600x600>', big: '1000x1000>'}
43
+ Paperclip.save_current_attachments_styles!
44
+ rebuild_model styles: {thumb: 'x100', export: 'x400>', croppable: '600x600>', big: '1000x1000>'}
45
+ expected_hash = { Dummy: {avatar: [:export, :thumb]} }
46
+ assert_equal expected_hash, Paperclip.missing_attachments_styles
47
+
48
+ ActiveRecord::Base.connection.create_table :books, force: true
49
+ class ::Book < ActiveRecord::Base
50
+ has_attached_file :cover, styles: {small: 'x100', large: '1000x1000>'}
51
+ has_attached_file :sample, styles: {thumb: 'x100'}
52
+ end
53
+
54
+ expected_hash = {
55
+ Dummy: {avatar: [:export, :thumb]},
56
+ Book: {sample: [:thumb], cover: [:large, :small]}
57
+ }
58
+ assert_equal expected_hash, Paperclip.missing_attachments_styles
59
+ Paperclip.save_current_attachments_styles!
60
+ assert_equal Hash.new, Paperclip.missing_attachments_styles
61
+ end
62
+
63
+ it "is able to calculate differences when a new attachment is added to a model" do
64
+ rebuild_model styles: {croppable: '600x600>', big: '1000x1000>'}
65
+ Paperclip.save_current_attachments_styles!
66
+
67
+ class ::Dummy
68
+ has_attached_file :photo, styles: {small: 'x100', large: '1000x1000>'}
69
+ end
70
+
71
+ expected_hash = {
72
+ Dummy: {photo: [:large, :small]}
73
+ }
74
+ assert_equal expected_hash, Paperclip.missing_attachments_styles
75
+ Paperclip.save_current_attachments_styles!
76
+ assert_equal Hash.new, Paperclip.missing_attachments_styles
77
+ end
78
+
79
+ # It's impossible to build styles hash without loading from database whole bunch of records
80
+ it "skips lambda-styles" do
81
+ rebuild_model styles: lambda{ |attachment| attachment.instance.other == 'a' ? {thumb: "50x50#"} : {large: "400x400"} }
82
+ assert_equal Hash.new, Paperclip.send(:current_attachments_styles)
83
+ end
84
+ end