kt-paperclip 7.2.2 → 8.0.0

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 (203) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +24 -56
  4. data/lib/generators/paperclip/paperclip_generator.rb +3 -1
  5. data/lib/kt-paperclip.rb +2 -0
  6. data/lib/paperclip/attachment.rb +49 -30
  7. data/lib/paperclip/attachment_registry.rb +2 -0
  8. data/lib/paperclip/callbacks.rb +7 -4
  9. data/lib/paperclip/commands/imagemagick/geometry_parser.rb +63 -0
  10. data/lib/paperclip/commands/imagemagick/version_detector.rb +41 -0
  11. data/lib/paperclip/commands/imagemagick.rb +44 -0
  12. data/lib/paperclip/commands/runner.rb +38 -0
  13. data/lib/paperclip/commands/unix_file.rb +28 -0
  14. data/lib/paperclip/content_type_detector.rb +31 -32
  15. data/lib/paperclip/errors.rb +2 -0
  16. data/lib/paperclip/file_command_content_type_detector.rb +11 -12
  17. data/lib/paperclip/filename_cleaner.rb +2 -0
  18. data/lib/paperclip/geometry.rb +22 -7
  19. data/lib/paperclip/geometry_detector_factory.rb +11 -31
  20. data/lib/paperclip/geometry_parser_factory.rb +13 -17
  21. data/lib/paperclip/glue.rb +2 -0
  22. data/lib/paperclip/has_attached_file.rb +2 -0
  23. data/lib/paperclip/helpers.rb +5 -25
  24. data/lib/paperclip/interpolations/plural_cache.rb +2 -0
  25. data/lib/paperclip/interpolations.rb +2 -0
  26. data/lib/paperclip/io_adapters/abstract_adapter.rb +3 -1
  27. data/lib/paperclip/io_adapters/attachment_adapter.rb +11 -0
  28. data/lib/paperclip/io_adapters/data_uri_adapter.rb +2 -0
  29. data/lib/paperclip/io_adapters/empty_string_adapter.rb +2 -0
  30. data/lib/paperclip/io_adapters/file_adapter.rb +2 -0
  31. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +2 -0
  32. data/lib/paperclip/io_adapters/identity_adapter.rb +2 -0
  33. data/lib/paperclip/io_adapters/nil_adapter.rb +2 -0
  34. data/lib/paperclip/io_adapters/registry.rb +2 -0
  35. data/lib/paperclip/io_adapters/stringio_adapter.rb +2 -0
  36. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +2 -0
  37. data/lib/paperclip/io_adapters/uri_adapter.rb +5 -13
  38. data/lib/paperclip/locales/fr.yml +18 -0
  39. data/lib/paperclip/locales/gd.yml +1 -1
  40. data/lib/paperclip/logger.rb +2 -0
  41. data/lib/paperclip/matchers/have_attached_file_matcher.rb +2 -0
  42. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +5 -3
  43. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +2 -0
  44. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +2 -0
  45. data/lib/paperclip/matchers.rb +2 -0
  46. data/lib/paperclip/media_type_spoof_detector.rb +3 -10
  47. data/lib/paperclip/missing_attachment_styles.rb +2 -0
  48. data/lib/paperclip/processor.rb +6 -19
  49. data/lib/paperclip/processor_helpers.rb +2 -0
  50. data/lib/paperclip/rails_environment.rb +2 -0
  51. data/lib/paperclip/railtie.rb +2 -0
  52. data/lib/paperclip/schema.rb +6 -4
  53. data/lib/paperclip/storage/filesystem.rb +2 -0
  54. data/lib/paperclip/storage/fog.rb +13 -4
  55. data/lib/paperclip/storage/s3.rb +27 -5
  56. data/lib/paperclip/storage.rb +2 -0
  57. data/lib/paperclip/style.rb +2 -0
  58. data/lib/paperclip/tempfile.rb +2 -0
  59. data/lib/paperclip/tempfile_factory.rb +2 -0
  60. data/lib/paperclip/thumbnail.rb +9 -10
  61. data/lib/paperclip/url_generator.rb +2 -0
  62. data/lib/paperclip/validators/attachment_content_type_validator.rb +2 -0
  63. data/lib/paperclip/validators/attachment_file_name_validator.rb +2 -0
  64. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +2 -0
  65. data/lib/paperclip/validators/attachment_presence_validator.rb +2 -0
  66. data/lib/paperclip/validators/attachment_size_validator.rb +2 -0
  67. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +2 -0
  68. data/lib/paperclip/validators.rb +2 -0
  69. data/lib/paperclip/version.rb +3 -1
  70. data/lib/paperclip.rb +25 -4
  71. data/lib/tasks/paperclip.rake +9 -4
  72. data/shoulda_macros/paperclip.rb +2 -0
  73. metadata +19 -538
  74. data/.codeclimate.yml +0 -17
  75. data/.github/FUNDING.yml +0 -3
  76. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  77. data/.github/ISSUE_TEMPLATE/custom.md +0 -10
  78. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  79. data/.gitignore +0 -19
  80. data/.hound.yml +0 -3
  81. data/.rubocop.yml +0 -1061
  82. data/.travis.yml +0 -45
  83. data/Appraisals +0 -30
  84. data/CONTRIBUTING.md +0 -85
  85. data/Gemfile +0 -19
  86. data/NEWS +0 -554
  87. data/RELEASING.md +0 -17
  88. data/Rakefile +0 -52
  89. data/UPGRADING +0 -17
  90. data/features/basic_integration.feature +0 -85
  91. data/features/migration.feature +0 -29
  92. data/features/rake_tasks.feature +0 -62
  93. data/features/step_definitions/attachment_steps.rb +0 -120
  94. data/features/step_definitions/html_steps.rb +0 -15
  95. data/features/step_definitions/rails_steps.rb +0 -257
  96. data/features/step_definitions/s3_steps.rb +0 -14
  97. data/features/step_definitions/web_steps.rb +0 -106
  98. data/features/support/env.rb +0 -12
  99. data/features/support/fakeweb.rb +0 -11
  100. data/features/support/file_helpers.rb +0 -34
  101. data/features/support/fixtures/boot_config.txt +0 -15
  102. data/features/support/fixtures/gemfile.txt +0 -5
  103. data/features/support/fixtures/preinitializer.txt +0 -20
  104. data/features/support/paths.rb +0 -28
  105. data/features/support/rails.rb +0 -39
  106. data/features/support/selectors.rb +0 -19
  107. data/gemfiles/4.2.gemfile +0 -20
  108. data/gemfiles/5.0.gemfile +0 -20
  109. data/gemfiles/5.1.gemfile +0 -20
  110. data/gemfiles/5.2.gemfile +0 -20
  111. data/gemfiles/6.0.gemfile +0 -20
  112. data/gemfiles/6.1.gemfile +0 -21
  113. data/gemfiles/7.0.gemfile +0 -21
  114. data/paperclip.gemspec +0 -50
  115. data/spec/database.yml +0 -4
  116. data/spec/paperclip/attachment_definitions_spec.rb +0 -13
  117. data/spec/paperclip/attachment_processing_spec.rb +0 -79
  118. data/spec/paperclip/attachment_registry_spec.rb +0 -158
  119. data/spec/paperclip/attachment_spec.rb +0 -1590
  120. data/spec/paperclip/content_type_detector_spec.rb +0 -54
  121. data/spec/paperclip/file_command_content_type_detector_spec.rb +0 -40
  122. data/spec/paperclip/filename_cleaner_spec.rb +0 -13
  123. data/spec/paperclip/geometry_detector_spec.rb +0 -47
  124. data/spec/paperclip/geometry_parser_spec.rb +0 -73
  125. data/spec/paperclip/geometry_spec.rb +0 -267
  126. data/spec/paperclip/glue_spec.rb +0 -63
  127. data/spec/paperclip/has_attached_file_spec.rb +0 -78
  128. data/spec/paperclip/integration_spec.rb +0 -702
  129. data/spec/paperclip/interpolations_spec.rb +0 -270
  130. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +0 -160
  131. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +0 -140
  132. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +0 -88
  133. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +0 -17
  134. data/spec/paperclip/io_adapters/file_adapter_spec.rb +0 -131
  135. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +0 -142
  136. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +0 -8
  137. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +0 -25
  138. data/spec/paperclip/io_adapters/registry_spec.rb +0 -35
  139. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +0 -64
  140. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +0 -146
  141. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +0 -231
  142. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +0 -19
  143. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +0 -108
  144. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +0 -69
  145. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +0 -88
  146. data/spec/paperclip/media_type_spoof_detector_spec.rb +0 -126
  147. data/spec/paperclip/meta_class_spec.rb +0 -30
  148. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +0 -88
  149. data/spec/paperclip/paperclip_spec.rb +0 -196
  150. data/spec/paperclip/plural_cache_spec.rb +0 -37
  151. data/spec/paperclip/processor_helpers_spec.rb +0 -57
  152. data/spec/paperclip/processor_spec.rb +0 -26
  153. data/spec/paperclip/rails_environment_spec.rb +0 -30
  154. data/spec/paperclip/rake_spec.rb +0 -103
  155. data/spec/paperclip/schema_spec.rb +0 -252
  156. data/spec/paperclip/storage/filesystem_spec.rb +0 -102
  157. data/spec/paperclip/storage/fog_spec.rb +0 -606
  158. data/spec/paperclip/storage/s3_live_spec.rb +0 -188
  159. data/spec/paperclip/storage/s3_spec.rb +0 -1878
  160. data/spec/paperclip/style_spec.rb +0 -251
  161. data/spec/paperclip/tempfile_factory_spec.rb +0 -33
  162. data/spec/paperclip/tempfile_spec.rb +0 -35
  163. data/spec/paperclip/thumbnail_spec.rb +0 -504
  164. data/spec/paperclip/url_generator_spec.rb +0 -231
  165. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +0 -410
  166. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +0 -249
  167. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +0 -85
  168. data/spec/paperclip/validators/attachment_size_validator_spec.rb +0 -325
  169. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +0 -48
  170. data/spec/paperclip/validators_spec.rb +0 -179
  171. data/spec/spec_helper.rb +0 -46
  172. data/spec/support/assertions.rb +0 -84
  173. data/spec/support/fake_model.rb +0 -24
  174. data/spec/support/fake_rails.rb +0 -12
  175. data/spec/support/fixtures/12k.png +0 -0
  176. data/spec/support/fixtures/50x50.png +0 -0
  177. data/spec/support/fixtures/5k.png +0 -0
  178. data/spec/support/fixtures/animated +0 -0
  179. data/spec/support/fixtures/animated.gif +0 -0
  180. data/spec/support/fixtures/animated.unknown +0 -0
  181. data/spec/support/fixtures/aws_s3.yml +0 -13
  182. data/spec/support/fixtures/bad.png +0 -1
  183. data/spec/support/fixtures/empty.html +0 -1
  184. data/spec/support/fixtures/empty.xlsx +0 -0
  185. data/spec/support/fixtures/fog.yml +0 -8
  186. data/spec/support/fixtures/rotated.jpg +0 -0
  187. data/spec/support/fixtures/s3.yml +0 -8
  188. data/spec/support/fixtures/sample.xlsm +0 -0
  189. data/spec/support/fixtures/spaced file.jpg +0 -0
  190. data/spec/support/fixtures/spaced file.png +0 -0
  191. data/spec/support/fixtures/text.txt +0 -1
  192. data/spec/support/fixtures/twopage.pdf +0 -0
  193. data/spec/support/fixtures/uppercase.PNG +0 -0
  194. data/spec/support/matchers/accept.rb +0 -5
  195. data/spec/support/matchers/exist.rb +0 -5
  196. data/spec/support/matchers/have_column.rb +0 -23
  197. data/spec/support/mock_attachment.rb +0 -24
  198. data/spec/support/mock_interpolator.rb +0 -24
  199. data/spec/support/mock_url_generator_builder.rb +0 -26
  200. data/spec/support/model_reconstruction.rb +0 -72
  201. data/spec/support/reporting.rb +0 -11
  202. data/spec/support/test_data.rb +0 -13
  203. data/spec/support/version_helper.rb +0 -9
@@ -1,1590 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Paperclip::Attachment do
4
- it "is not present when file not set" do
5
- rebuild_class
6
- dummy = Dummy.new
7
- expect(dummy.avatar).to be_blank
8
- expect(dummy.avatar).to_not be_present
9
- end
10
-
11
- it "is present when the file is set" do
12
- rebuild_class
13
- dummy = Dummy.new
14
- dummy.avatar = File.new(fixture_file("50x50.png"), "rb")
15
- expect(dummy.avatar).to_not be_blank
16
- expect(dummy.avatar).to be_present
17
- end
18
-
19
- it "processes :original style first" do
20
- file = File.new(fixture_file("50x50.png"), "rb")
21
- rebuild_class styles: { small: "100x>", original: "42x42#" }
22
- dummy = Dummy.new
23
- dummy.avatar = file
24
- dummy.save
25
-
26
- # :small avatar should be 42px wide (processed original), not 50px (preprocessed original)
27
- expect(`identify -format "%w" "#{dummy.avatar.path(:small)}"`.strip).to eq "42"
28
-
29
- file.close
30
- end
31
-
32
- it "does not delete styles that don't get reprocessed" do
33
- file = File.new(fixture_file("50x50.png"), "rb")
34
- rebuild_class styles: {
35
- small: "100x>",
36
- large: "500x>",
37
- original: "42x42#"
38
- }
39
-
40
- dummy = Dummy.new
41
- dummy.avatar = file
42
- dummy.save
43
-
44
- expect(dummy.avatar.path(:small)).to exist
45
- expect(dummy.avatar.path(:large)).to exist
46
- expect(dummy.avatar.path(:original)).to exist
47
-
48
- dummy.avatar.reprocess!(:small)
49
-
50
- expect(dummy.avatar.path(:small)).to exist
51
- expect(dummy.avatar.path(:large)).to exist
52
- expect(dummy.avatar.path(:original)).to exist
53
- end
54
-
55
- it "reprocess works with virtual content_type attribute" do
56
- rebuild_class styles: { small: "100x>" }
57
- modify_table { |t| t.remove :avatar_content_type }
58
- Dummy.send :attr_accessor, :avatar_content_type
59
- Dummy.validates_attachment_content_type(
60
- :avatar,
61
- content_type: %w(image/jpeg image/png)
62
- )
63
- Dummy.create!(avatar: File.new(fixture_file("50x50.png"), "rb"))
64
-
65
- dummy = Dummy.first
66
- dummy.avatar.reprocess!(:small)
67
-
68
- expect(dummy.avatar.path(:small)).to exist
69
- end
70
-
71
- context "having a not empty hash as a default option" do
72
- before do
73
- @old_default_options = Paperclip::Attachment.default_options.dup
74
- @new_default_options = { convert_options: { all: "-background white" } }
75
- Paperclip::Attachment.default_options.merge!(@new_default_options)
76
- end
77
-
78
- after do
79
- Paperclip::Attachment.default_options.merge!(@old_default_options)
80
- end
81
-
82
- it "deep merges when it is overridden" do
83
- new_options = { convert_options: { thumb: "-thumbnailize" } }
84
- attachment = Paperclip::Attachment.new(:name, :instance, new_options)
85
-
86
- expect(Paperclip::Attachment.default_options.deep_merge(new_options)).to eq attachment.instance_variable_get("@options")
87
- end
88
- end
89
-
90
- it "handles a boolean second argument to #url" do
91
- mock_url_generator_builder = MockUrlGeneratorBuilder.new
92
- attachment = Paperclip::Attachment.new(
93
- :name,
94
- FakeModel.new,
95
- url_generator: mock_url_generator_builder
96
- )
97
-
98
- attachment.url(:style_name, true)
99
- expect(mock_url_generator_builder.has_generated_url_with_options?(timestamp: true, escape: true)).to eq true
100
-
101
- attachment.url(:style_name, false)
102
- expect(mock_url_generator_builder.has_generated_url_with_options?(timestamp: false, escape: true)).to eq true
103
- end
104
-
105
- it "passes the style and options through to the URL generator on #url" do
106
- mock_url_generator_builder = MockUrlGeneratorBuilder.new
107
- attachment = Paperclip::Attachment.new(
108
- :name,
109
- FakeModel.new,
110
- url_generator: mock_url_generator_builder
111
- )
112
-
113
- attachment.url(:style_name, options: :values)
114
- expect(mock_url_generator_builder.has_generated_url_with_options?(options: :values)).to eq true
115
- end
116
-
117
- it "passes default options through when #url is given one argument" do
118
- mock_url_generator_builder = MockUrlGeneratorBuilder.new
119
- attachment = Paperclip::Attachment.new(:name,
120
- FakeModel.new,
121
- url_generator: mock_url_generator_builder,
122
- use_timestamp: true)
123
-
124
- attachment.url(:style_name)
125
- assert mock_url_generator_builder.has_generated_url_with_options?(escape: true, timestamp: true)
126
- end
127
-
128
- it "passes default style and options through when #url is given no arguments" do
129
- mock_url_generator_builder = MockUrlGeneratorBuilder.new
130
- attachment = Paperclip::Attachment.new(:name,
131
- FakeModel.new,
132
- default_style: "default style",
133
- url_generator: mock_url_generator_builder,
134
- use_timestamp: true)
135
-
136
- attachment.url
137
- assert mock_url_generator_builder.has_generated_url_with_options?(escape: true, timestamp: true)
138
- assert mock_url_generator_builder.has_generated_url_with_style_name?("default style")
139
- end
140
-
141
- it "passes the option timestamp: true if :use_timestamp is true and :timestamp is not passed" do
142
- mock_url_generator_builder = MockUrlGeneratorBuilder.new
143
- attachment = Paperclip::Attachment.new(:name,
144
- FakeModel.new,
145
- url_generator: mock_url_generator_builder,
146
- use_timestamp: true)
147
-
148
- attachment.url(:style_name)
149
- assert mock_url_generator_builder.has_generated_url_with_options?(escape: true, timestamp: true)
150
- end
151
-
152
- it "passes the option timestamp: false if :use_timestamp is false and :timestamp is not passed" do
153
- mock_url_generator_builder = MockUrlGeneratorBuilder.new
154
- attachment = Paperclip::Attachment.new(:name,
155
- FakeModel.new,
156
- url_generator: mock_url_generator_builder,
157
- use_timestamp: false)
158
-
159
- attachment.url(:style_name)
160
- assert mock_url_generator_builder.has_generated_url_with_options?(escape: true, timestamp: false)
161
- end
162
-
163
- it "does not change the :timestamp if :timestamp is passed" do
164
- mock_url_generator_builder = MockUrlGeneratorBuilder.new
165
- attachment = Paperclip::Attachment.new(:name,
166
- FakeModel.new,
167
- url_generator: mock_url_generator_builder,
168
- use_timestamp: false)
169
-
170
- attachment.url(:style_name, timestamp: true)
171
- assert mock_url_generator_builder.has_generated_url_with_options?(escape: true, timestamp: true)
172
- end
173
-
174
- it "renders JSON as default style" do
175
- mock_url_generator_builder = MockUrlGeneratorBuilder.new
176
- attachment = Paperclip::Attachment.new(:name,
177
- FakeModel.new,
178
- default_style: "default style",
179
- url_generator: mock_url_generator_builder)
180
-
181
- attachment.as_json
182
- assert mock_url_generator_builder.has_generated_url_with_style_name?("default style")
183
- end
184
-
185
- it "passes the option escape: true if :escape_url is true and :escape is not passed" do
186
- mock_url_generator_builder = MockUrlGeneratorBuilder.new
187
- attachment = Paperclip::Attachment.new(:name,
188
- FakeModel.new,
189
- url_generator: mock_url_generator_builder,
190
- escape_url: true)
191
-
192
- attachment.url(:style_name)
193
- assert mock_url_generator_builder.has_generated_url_with_options?(escape: true)
194
- end
195
-
196
- it "passes the option escape: false if :escape_url is false and :escape is not passed" do
197
- mock_url_generator_builder = MockUrlGeneratorBuilder.new
198
- attachment = Paperclip::Attachment.new(:name,
199
- FakeModel.new,
200
- url_generator: mock_url_generator_builder,
201
- escape_url: false)
202
-
203
- attachment.url(:style_name)
204
- assert mock_url_generator_builder.has_generated_url_with_options?(escape: false)
205
- end
206
-
207
- it "returns the path based on the url by default" do
208
- @attachment = attachment url: "/:class/:id/:basename"
209
- @model = @attachment.instance
210
- @model.id = 1234
211
- @model.avatar_file_name = "fake.jpg"
212
- assert_equal "#{Rails.root}/public/fake_models/1234/fake", @attachment.path
213
- end
214
-
215
- it "defaults to a path that scales" do
216
- avatar_attachment = attachment
217
- model = avatar_attachment.instance
218
- model.id = 1234
219
- model.avatar_file_name = "fake.jpg"
220
- expected_path = "#{Rails.root}/public/system/fake_models/avatars/000/001/234/original/fake.jpg"
221
- assert_equal expected_path, avatar_attachment.path
222
- end
223
-
224
- it "renders JSON as the URL to the attachment" do
225
- avatar_attachment = attachment
226
- model = avatar_attachment.instance
227
- model.id = 1234
228
- model.avatar_file_name = "fake.jpg"
229
- assert_equal attachment.url, attachment.as_json
230
- end
231
-
232
- it "renders JSON from the model when requested by :methods" do
233
- rebuild_model
234
- dummy = Dummy.new
235
- dummy.id = 1234
236
- dummy.avatar_file_name = "fake.jpg"
237
- allow(dummy).to receive(:new_record?).and_return(false)
238
- expected_string = '{"avatar":"/system/dummies/avatars/000/001/234/original/fake.jpg"}'
239
- # active_model pre-3.2 checks only by calling any? on it, thus it doesn't work if it is empty
240
- assert_equal expected_string, dummy.to_json(only: [:dummy_key_for_old_active_model], methods: [:avatar])
241
- end
242
-
243
- context "Attachment default_options" do
244
- before do
245
- rebuild_model
246
- @old_default_options = Paperclip::Attachment.default_options.dup
247
- @new_default_options = @old_default_options.merge(
248
- path: "argle/bargle",
249
- url: "fooferon",
250
- default_url: "not here.png"
251
- )
252
- end
253
-
254
- after do
255
- Paperclip::Attachment.default_options.merge! @old_default_options
256
- end
257
-
258
- it "is overrideable" do
259
- Paperclip::Attachment.default_options.merge!(@new_default_options)
260
- @new_default_options.keys.each do |key|
261
- assert_equal @new_default_options[key],
262
- Paperclip::Attachment.default_options[key]
263
- end
264
- end
265
-
266
- context "without an Attachment" do
267
- before do
268
- rebuild_model default_url: "default.url"
269
- @dummy = Dummy.new
270
- end
271
-
272
- it "returns false when asked exists?" do
273
- assert !@dummy.avatar.exists?
274
- end
275
-
276
- it "#url returns the default_url" do
277
- expect(@dummy.avatar.url).to eq "default.url"
278
- end
279
- end
280
-
281
- context "on an Attachment" do
282
- before do
283
- @dummy = Dummy.new
284
- @attachment = @dummy.avatar
285
- end
286
-
287
- Paperclip::Attachment.default_options.keys.each do |key|
288
- it "is the default_options for #{key}" do
289
- assert_equal @old_default_options[key],
290
- @attachment.instance_variable_get("@options")[key],
291
- key.to_s
292
- end
293
- end
294
-
295
- context "when redefined" do
296
- before do
297
- Paperclip::Attachment.default_options.merge!(@new_default_options)
298
- @dummy = Dummy.new
299
- @attachment = @dummy.avatar
300
- end
301
-
302
- Paperclip::Attachment.default_options.keys.each do |key|
303
- it "is the new default_options for #{key}" do
304
- assert_equal @new_default_options[key],
305
- @attachment.instance_variable_get("@options")[key],
306
- key.to_s
307
- end
308
- end
309
- end
310
- end
311
- end
312
-
313
- context "An attachment with similarly named interpolations" do
314
- before do
315
- rebuild_model path: ":id.omg/:id-bbq/:idwhat/:id_partition.wtf"
316
- @dummy = Dummy.new
317
-
318
- allow(@dummy).to receive(:id).and_return(1024)
319
- @file = File.new(fixture_file("5k.png"), "rb")
320
- @dummy.avatar = @file
321
- end
322
-
323
- after { @file.close }
324
-
325
- it "makes sure that they are interpolated correctly" do
326
- assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path
327
- end
328
- end
329
-
330
- context "An attachment with :timestamp interpolations" do
331
- before do
332
- @file = StringIO.new("...")
333
- @zone = "UTC"
334
- allow(Time).to receive(:zone).and_return(@zone)
335
- @zone_default = "Eastern Time (US & Canada)"
336
- allow(Time).to receive(:zone_default).and_return(@zone_default)
337
- end
338
-
339
- context "using default time zone" do
340
- before do
341
- rebuild_model path: ":timestamp", use_default_time_zone: true
342
- @dummy = Dummy.new
343
- @dummy.avatar = @file
344
- end
345
-
346
- it "returns a time in the default zone" do
347
- assert_equal @dummy.avatar_updated_at.in_time_zone(@zone_default).to_s, @dummy.avatar.path
348
- end
349
- end
350
-
351
- context "using per-thread time zone" do
352
- before do
353
- rebuild_model path: ":timestamp", use_default_time_zone: false
354
- @dummy = Dummy.new
355
- @dummy.avatar = @file
356
- end
357
-
358
- it "returns a time in the per-thread zone" do
359
- assert_equal @dummy.avatar_updated_at.in_time_zone(@zone).to_s, @dummy.avatar.path
360
- end
361
- end
362
- end
363
-
364
- context "An attachment with :hash interpolations" do
365
- before do
366
- @file = File.open(fixture_file("5k.png"))
367
- end
368
-
369
- after do
370
- @file.close
371
- end
372
-
373
- it "raises if no secret is provided" do
374
- rebuild_model path: ":hash"
375
- @attachment = Dummy.new.avatar
376
- @attachment.assign @file
377
-
378
- assert_raises ArgumentError do
379
- @attachment.path
380
- end
381
- end
382
-
383
- context "when secret is set" do
384
- before do
385
- rebuild_model path: ":hash",
386
- hash_secret: "w00t",
387
- hash_data: ":class/:attachment/:style/:filename"
388
- @attachment = Dummy.new.avatar
389
- @attachment.assign @file
390
- end
391
-
392
- it "results in the correct interpolation" do
393
- assert_equal "dummies/avatars/original/5k.png",
394
- @attachment.send(:interpolate, @attachment.options[:hash_data])
395
- assert_equal "dummies/avatars/thumb/5k.png",
396
- @attachment.send(:interpolate, @attachment.options[:hash_data], :thumb)
397
- end
398
-
399
- it "results in a correct hash" do
400
- assert_equal "0a59e9142bba11576de1d353d8747b1acad5ad34", @attachment.path
401
- assert_equal "b39a062c1e62e85a6c785ed00cf3bebf5f850e2b", @attachment.path(:thumb)
402
- end
403
- end
404
- end
405
-
406
- context "An attachment with a :rails_env interpolation" do
407
- before do
408
- @rails_env = "blah"
409
- @id = 1024
410
- rebuild_model path: ":rails_env/:id.png"
411
- @dummy = Dummy.new
412
- allow(@dummy).to receive(:id).and_return(@id)
413
- @file = StringIO.new(".")
414
- @dummy.avatar = @file
415
- allow(Rails).to receive(:env).and_return(@rails_env)
416
- end
417
-
418
- it "returns the proper path" do
419
- assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path
420
- end
421
- end
422
-
423
- context "An attachment with a default style and an extension interpolation" do
424
- before do
425
- rebuild_model path: ":basename.:extension",
426
- styles: { default: ["100x100", :jpg] },
427
- default_style: :default
428
- @attachment = Dummy.new.avatar
429
- @file = File.open(fixture_file("5k.png"))
430
- allow(@file).to receive(:original_filename).and_return("file.png")
431
- end
432
- it "returns the right extension for the path" do
433
- @attachment.assign(@file)
434
- assert_equal "file.jpg", @attachment.path
435
- end
436
- end
437
-
438
- context "An attachment with :convert_options" do
439
- before do
440
- rebuild_model styles: {
441
- thumb: "100x100",
442
- large: "400x400"
443
- },
444
- convert_options: {
445
- all: "-do_stuff",
446
- thumb: "-thumbnailize"
447
- }
448
- @dummy = Dummy.new
449
- @dummy.avatar
450
- end
451
-
452
- it "reports the correct options when sent #extra_options_for(:thumb)" do
453
- assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
454
- end
455
-
456
- it "reports the correct options when sent #extra_options_for(:large)" do
457
- assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
458
- end
459
- end
460
-
461
- context "An attachment with :source_file_options" do
462
- before do
463
- rebuild_model styles: {
464
- thumb: "100x100",
465
- large: "400x400"
466
- },
467
- source_file_options: {
468
- all: "-density 400",
469
- thumb: "-depth 8"
470
- }
471
- @dummy = Dummy.new
472
- @dummy.avatar
473
- end
474
-
475
- it "reports the correct options when sent #extra_source_file_options_for(:thumb)" do
476
- assert_equal "-depth 8 -density 400", @dummy.avatar.send(:extra_source_file_options_for, :thumb), @dummy.avatar.source_file_options.inspect
477
- end
478
-
479
- it "reports the correct options when sent #extra_source_file_options_for(:large)" do
480
- assert_equal "-density 400", @dummy.avatar.send(:extra_source_file_options_for, :large)
481
- end
482
- end
483
-
484
- context "An attachment with :only_process" do
485
- before do
486
- rebuild_model styles: {
487
- thumb: "100x100",
488
- large: "400x400"
489
- },
490
- only_process: [:thumb]
491
- @file = StringIO.new("...")
492
- @attachment = Dummy.new.avatar
493
- end
494
-
495
- it "only processes the provided style" do
496
- expect(@attachment).to receive(:post_process).with(:thumb)
497
- expect(@attachment).to receive(:post_process).with(:large).never
498
- @attachment.assign(@file)
499
- end
500
- end
501
-
502
- context "An attachment with :only_process that is a proc" do
503
- before do
504
- rebuild_model styles: {
505
- thumb: "100x100",
506
- large: "400x400"
507
- },
508
- only_process: lambda { |_attachment| [:thumb] }
509
-
510
- @file = StringIO.new("...")
511
- @attachment = Dummy.new.avatar
512
- end
513
-
514
- it "only processes the provided style" do
515
- expect(@attachment).to receive(:post_process).with(:thumb)
516
- expect(@attachment).to receive(:post_process).with(:large).never
517
- @attachment.assign(@file)
518
- @attachment.save
519
- end
520
- end
521
-
522
- context "An attachment with :convert_options that is a proc" do
523
- before do
524
- rebuild_model styles: {
525
- thumb: "100x100",
526
- large: "400x400"
527
- },
528
- convert_options: {
529
- all: lambda { |i| i.all },
530
- thumb: lambda { |i| i.thumb }
531
- }
532
- Dummy.class_eval do
533
- def all; "-all"; end
534
-
535
- def thumb; "-thumb"; end
536
- end
537
- @dummy = Dummy.new
538
- @dummy.avatar
539
- end
540
-
541
- it "reports the correct options when sent #extra_options_for(:thumb)" do
542
- assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
543
- end
544
-
545
- it "reports the correct options when sent #extra_options_for(:large)" do
546
- assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
547
- end
548
- end
549
-
550
- context "An attachment with :path that is a proc" do
551
- before do
552
- rebuild_model path: lambda { |attachment| "path/#{attachment.instance.other}.:extension" }
553
-
554
- @file = File.new(fixture_file("5k.png"), "rb")
555
- @dummyA = Dummy.new(other: "a")
556
- @dummyA.avatar = @file
557
- @dummyB = Dummy.new(other: "b")
558
- @dummyB.avatar = @file
559
- end
560
-
561
- after { @file.close }
562
-
563
- it "returns correct path" do
564
- assert_equal "path/a.png", @dummyA.avatar.path
565
- assert_equal "path/b.png", @dummyB.avatar.path
566
- end
567
- end
568
-
569
- context "An attachment with :styles that is a proc" do
570
- before do
571
- rebuild_model styles: lambda { |_attachment| { thumb: "50x50#", large: "400x400" } }
572
-
573
- @attachment = Dummy.new.avatar
574
- end
575
-
576
- it "has the correct geometry" do
577
- assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
578
- end
579
- end
580
-
581
- context "An attachment with conditional :styles that is a proc" do
582
- before do
583
- rebuild_model styles: lambda { |attachment| attachment.instance.other == "a" ? { thumb: "50x50#" } : { large: "400x400" } }
584
-
585
- @dummy = Dummy.new(other: "a")
586
- end
587
-
588
- it "has the correct styles for the assigned instance values" do
589
- assert_equal "50x50#", @dummy.avatar.styles[:thumb][:geometry]
590
- assert_nil @dummy.avatar.styles[:large]
591
-
592
- @dummy.other = "b"
593
-
594
- assert_equal "400x400", @dummy.avatar.styles[:large][:geometry]
595
- assert_nil @dummy.avatar.styles[:thumb]
596
- end
597
- end
598
-
599
- geometry_specs = [
600
- [lambda { |_z| "50x50#" }, :png],
601
- lambda { |_z| "50x50#" },
602
- { geometry: lambda { |_z| "50x50#" } }
603
- ]
604
- geometry_specs.each do |geometry_spec|
605
- context "An attachment geometry like #{geometry_spec}" do
606
- before do
607
- rebuild_model styles: { normal: geometry_spec }
608
- @attachment = Dummy.new.avatar
609
- end
610
-
611
- context "when assigned" do
612
- before do
613
- @file = StringIO.new(".")
614
- @attachment.assign(@file)
615
- end
616
-
617
- it "has the correct geometry" do
618
- assert_equal "50x50#", @attachment.styles[:normal][:geometry]
619
- end
620
- end
621
- end
622
- end
623
-
624
- context "An attachment with both 'normal' and hash-style styles" do
625
- before do
626
- rebuild_model styles: {
627
- normal: ["50x50#", :png],
628
- hash: { geometry: "50x50#", format: :png }
629
- }
630
- @dummy = Dummy.new
631
- @attachment = @dummy.avatar
632
- end
633
-
634
- [:processors, :whiny, :convert_options, :geometry, :format].each do |field|
635
- it "has the same #{field} field" do
636
- assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field]
637
- end
638
- end
639
- end
640
-
641
- context "An attachment with :processors that is a proc" do
642
- before do
643
- class Paperclip::Test < Paperclip::Processor; end
644
- @file = StringIO.new("...")
645
- allow(Paperclip::Test).to receive(:make).and_return(@file)
646
-
647
- rebuild_model styles: { normal: "" }, processors: lambda { |_a| [:test] }
648
- @attachment = Dummy.new.avatar
649
- end
650
-
651
- context "when assigned" do
652
- before do
653
- @attachment.assign(StringIO.new("."))
654
- end
655
-
656
- it "has the correct processors" do
657
- assert_equal [:test], @attachment.styles[:normal][:processors]
658
- end
659
- end
660
- end
661
-
662
- context "An attachment with erroring processor" do
663
- before do
664
- rebuild_model processor: [:thumbnail], styles: { small: "" }, whiny_thumbnails: true
665
- @dummy = Dummy.new
666
- @file = StringIO.new("...")
667
- allow(@file).to receive(:to_tempfile).and_return(@file)
668
- end
669
-
670
- context "when error is meaningful for the end user" do
671
- before do
672
- expect(Paperclip::Thumbnail).to receive(:make).and_raise(
673
- Paperclip::Errors::NotIdentifiedByImageMagickError,
674
- "cannot be processed."
675
- )
676
- end
677
-
678
- it "correctly forwards processing error message to the instance" do
679
- @dummy.avatar = @file
680
- @dummy.valid?
681
- assert_contains(
682
- @dummy.errors.full_messages,
683
- "Avatar cannot be processed."
684
- )
685
- end
686
- end
687
-
688
- context "when error is intended for the developer" do
689
- before do
690
- expect(Paperclip::Thumbnail).to receive(:make).and_raise(
691
- Paperclip::Errors::CommandNotFoundError
692
- )
693
- end
694
-
695
- it "propagates the error" do
696
- assert_raises(Paperclip::Errors::CommandNotFoundError) do
697
- @dummy.avatar = @file
698
- end
699
- end
700
- end
701
- end
702
-
703
- context "An attachment with multiple processors" do
704
- before do
705
- class Paperclip::Test < Paperclip::Processor; end
706
- @style_params = { once: { one: 1, two: 2 } }
707
- rebuild_model processors: [:thumbnail, :test], styles: @style_params
708
- @dummy = Dummy.new
709
- @file = StringIO.new("...")
710
- allow(@file).to receive(:close)
711
- allow(Paperclip::Test).to receive(:make).and_return(@file)
712
- allow(Paperclip::Thumbnail).to receive(:make).and_return(@file)
713
- end
714
-
715
- context "when assigned" do
716
- it "calls #make on all specified processors" do
717
- @dummy.avatar = @file
718
-
719
- expect(Paperclip::Thumbnail).to have_received(:make)
720
- expect(Paperclip::Test).to have_received(:make)
721
- end
722
-
723
- it "calls #make with the right parameters passed as second argument" do
724
- expected_params = @style_params[:once].merge(
725
- style: :once,
726
- processors: [:thumbnail, :test],
727
- whiny: true,
728
- convert_options: "",
729
- source_file_options: ""
730
- )
731
-
732
- @dummy.avatar = @file
733
-
734
- expect(Paperclip::Thumbnail).to have_received(:make).with(anything, expected_params, anything)
735
- end
736
-
737
- it "calls #make with attachment passed as third argument" do
738
- @dummy.avatar = @file
739
-
740
- expect(Paperclip::Test).to have_received(:make).with(anything, anything, @dummy.avatar)
741
- end
742
-
743
- it "calls #make and unlinks intermediary files afterward" do
744
- expect(@dummy.avatar).to receive(:unlink_files).with([@file, @file])
745
-
746
- @dummy.avatar = @file
747
- end
748
- end
749
- end
750
-
751
- context "An attachment with a processor that returns original file" do
752
- before do
753
- class Paperclip::Test < Paperclip::Processor
754
- def make; @file; end
755
- end
756
- rebuild_model processors: [:test], styles: { once: "100x100" }
757
- @file = StringIO.new("...")
758
- allow(@file).to receive(:close)
759
- @dummy = Dummy.new
760
- end
761
-
762
- context "when assigned" do
763
- it "#calls #make and doesn't unlink the original file" do
764
- expect(@dummy.avatar).to receive(:unlink_files).with([])
765
-
766
- @dummy.avatar = @file
767
- end
768
- end
769
- end
770
-
771
- it "includes the filesystem module when loading the filesystem storage" do
772
- rebuild_model storage: :filesystem
773
- @dummy = Dummy.new
774
- assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
775
- end
776
-
777
- it "includes the filesystem module even if capitalization is wrong" do
778
- rebuild_model storage: :FileSystem
779
- @dummy = Dummy.new
780
- assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
781
-
782
- rebuild_model storage: :Filesystem
783
- @dummy = Dummy.new
784
- assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
785
- end
786
-
787
- it "converts underscored storage name to camelcase" do
788
- rebuild_model storage: :not_here
789
- @dummy = Dummy.new
790
- exception = assert_raises(Paperclip::Errors::StorageMethodNotFound, /NotHere/) do
791
- @dummy.avatar
792
- end
793
- end
794
-
795
- it "raises an error if you try to include a storage module that doesn't exist" do
796
- rebuild_model storage: :not_here
797
- @dummy = Dummy.new
798
- assert_raises(Paperclip::Errors::StorageMethodNotFound) do
799
- @dummy.avatar
800
- end
801
- end
802
-
803
- context "An attachment with styles but no processors defined" do
804
- before do
805
- rebuild_model processors: [], styles: { something: "1" }
806
- @dummy = Dummy.new
807
- @file = StringIO.new("...")
808
- end
809
- it "raises when assigned to" do
810
- assert_raises(RuntimeError) { @dummy.avatar = @file }
811
- end
812
- end
813
-
814
- context "An attachment without styles and with no processors defined" do
815
- before do
816
- rebuild_model processors: [], styles: {}
817
- @dummy = Dummy.new
818
- @file = StringIO.new("...")
819
- end
820
- it "does not raise when assigned to" do
821
- @dummy.avatar = @file
822
- end
823
- end
824
-
825
- context "Assigning an attachment with post_process hooks" do
826
- before do
827
- rebuild_class styles: { something: "100x100#" }
828
- Dummy.class_eval do
829
- before_avatar_post_process :do_before_avatar
830
- after_avatar_post_process :do_after_avatar
831
- before_post_process :do_before_all
832
- after_post_process :do_after_all
833
- def do_before_avatar; end
834
-
835
- def do_after_avatar; end
836
-
837
- def do_before_all; end
838
-
839
- def do_after_all; end
840
- end
841
- @file = StringIO.new(".")
842
- allow(@file).to receive(:to_tempfile).and_return(@file)
843
- @dummy = Dummy.new
844
- allow(Paperclip::Thumbnail).to receive(:make).and_return(@file)
845
- @attachment = @dummy.avatar
846
- end
847
-
848
- it "calls the defined callbacks when assigned" do
849
- expect(@dummy).to receive(:do_before_avatar)
850
- expect(@dummy).to receive(:do_after_avatar)
851
- expect(@dummy).to receive(:do_before_all)
852
- expect(@dummy).to receive(:do_after_all)
853
- expect(Paperclip::Thumbnail).to receive(:make).and_return(@file)
854
- @dummy.avatar = @file
855
- end
856
-
857
- it "does not cancel the processing if a before_post_process returns nil" do
858
- expect(@dummy).to receive(:do_before_avatar).and_return(nil)
859
- expect(@dummy).to receive(:do_after_avatar)
860
- expect(@dummy).to receive(:do_before_all).and_return(nil)
861
- expect(@dummy).to receive(:do_after_all)
862
- expect(Paperclip::Thumbnail).to receive(:make).and_return(@file)
863
- @dummy.avatar = @file
864
- end
865
-
866
- it "cancels the processing if a before_post_process returns false" do
867
- expect(@dummy).to receive(:do_before_avatar).never
868
- expect(@dummy).to receive(:do_after_avatar).never
869
- expect(@dummy).to receive(:do_before_all).and_return(false)
870
- expect(@dummy).to receive(:do_after_all)
871
- expect(Paperclip::Thumbnail).not_to receive(:make)
872
- @dummy.avatar = @file
873
- end
874
-
875
- it "cancels the processing if a before_avatar_post_process returns false" do
876
- expect(@dummy).to receive(:do_before_avatar).and_return(false)
877
- expect(@dummy).to receive(:do_after_avatar)
878
- expect(@dummy).to receive(:do_before_all).and_return(true)
879
- expect(@dummy).to receive(:do_after_all)
880
- expect(Paperclip::Thumbnail).not_to receive(:make)
881
- @dummy.avatar = @file
882
- end
883
-
884
- it "should not call process hooks if validation fails" do
885
- Dummy.class_eval do
886
- validates_attachment_content_type :avatar, content_type: 'image/jpeg'
887
- end
888
- expect(@dummy).not_to receive(:do_before_avatar)
889
- expect(@dummy).not_to receive(:do_after_avatar)
890
- expect(@dummy).not_to receive(:do_before_all)
891
- expect(@dummy).not_to receive(:do_after_all)
892
- expect(Paperclip::Thumbnail).not_to receive(:make)
893
- @dummy.avatar = @file
894
- end
895
-
896
- it "should call process hooks if validation would fail but check validity flag is false" do
897
- Dummy.class_eval do
898
- validates_attachment_content_type :avatar, content_type: 'image/jpeg'
899
- end
900
- @dummy.avatar.options[:check_validity_before_processing] = false
901
- expect(@dummy).to receive(:do_before_avatar)
902
- expect(@dummy).to receive(:do_after_avatar)
903
- expect(@dummy).to receive(:do_before_all)
904
- expect(@dummy).to receive(:do_after_all)
905
- expect(Paperclip::Thumbnail).to receive(:make).and_return(@file)
906
- @dummy.avatar = @file
907
- end
908
- end
909
-
910
- context "Assigning an attachment" do
911
- before do
912
- rebuild_model styles: { something: "100x100#" }
913
- @file = File.new(fixture_file("5k.png"), "rb")
914
- @dummy = Dummy.new
915
- @dummy.avatar = @file
916
- end
917
-
918
- it "strips whitespace from original_filename field" do
919
- assert_equal "5k.png", @dummy.avatar.original_filename
920
- end
921
-
922
- it "strips whitespace from content_type field" do
923
- assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
924
- end
925
- end
926
-
927
- context "Assigning an attachment" do
928
- before do
929
- rebuild_model styles: { something: "100x100#" }
930
- @file = File.new(fixture_file("5k.png"), "rb")
931
- @dummy = Dummy.new
932
- @dummy.avatar = @file
933
- end
934
-
935
- it "makes sure the content_type is a string" do
936
- assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
937
- end
938
- end
939
-
940
- context "Attachment with strange letters" do
941
- before do
942
- rebuild_model
943
- @file = File.new(fixture_file("5k.png"), "rb")
944
- allow(@file).to receive(:original_filename).and_return("sheep_say_bæ.png")
945
- @dummy = Dummy.new
946
- @dummy.avatar = @file
947
- end
948
-
949
- it "does not remove strange letters" do
950
- assert_equal "sheep_say_bæ.png", @dummy.avatar.original_filename
951
- end
952
- end
953
-
954
- context "Attachment with reserved filename" do
955
- before do
956
- rebuild_model
957
- @file = Tempfile.new(["filename", "png"])
958
- end
959
-
960
- after do
961
- @file.unlink
962
- end
963
-
964
- context "with default configuration" do
965
- "&$+,/:;=?@<>[]{}|\^~%# ".split(//).each do |character|
966
- context "with character #{character}" do
967
- context "at beginning of filename" do
968
- before do
969
- allow(@file).to receive(:original_filename).and_return("#{character}filename.png")
970
- @dummy = Dummy.new
971
- @dummy.avatar = @file
972
- end
973
-
974
- it "converts special character into underscore" do
975
- assert_equal "_filename.png", @dummy.avatar.original_filename
976
- end
977
- end
978
-
979
- context "at end of filename" do
980
- before do
981
- allow(@file).to receive(:original_filename).and_return("filename.png#{character}")
982
- @dummy = Dummy.new
983
- @dummy.avatar = @file
984
- end
985
-
986
- it "converts special character into underscore" do
987
- assert_equal "filename.png_", @dummy.avatar.original_filename
988
- end
989
- end
990
-
991
- context "in the middle of filename" do
992
- before do
993
- allow(@file).to receive(:original_filename).and_return("file#{character}name.png")
994
- @dummy = Dummy.new
995
- @dummy.avatar = @file
996
- end
997
-
998
- it "converts special character into underscore" do
999
- assert_equal "file_name.png", @dummy.avatar.original_filename
1000
- end
1001
- end
1002
- end
1003
- end
1004
- end
1005
-
1006
- context "with specified regexp replacement" do
1007
- before do
1008
- @old_defaults = Paperclip::Attachment.default_options.dup
1009
- end
1010
-
1011
- after do
1012
- Paperclip::Attachment.default_options.merge! @old_defaults
1013
- end
1014
-
1015
- context "as another regexp" do
1016
- before do
1017
- Paperclip::Attachment.default_options.merge! restricted_characters: /o/
1018
-
1019
- allow(@file).to receive(:original_filename).and_return("goood.png")
1020
- @dummy = Dummy.new
1021
- @dummy.avatar = @file
1022
- end
1023
-
1024
- it "matches and converts that character" do
1025
- assert_equal "g___d.png", @dummy.avatar.original_filename
1026
- end
1027
- end
1028
-
1029
- context "as nil" do
1030
- before do
1031
- Paperclip::Attachment.default_options.merge! restricted_characters: nil
1032
-
1033
- allow(@file).to receive(:original_filename).and_return("goood.png")
1034
- @dummy = Dummy.new
1035
- @dummy.avatar = @file
1036
- end
1037
-
1038
- it "ignores and returns the original file name" do
1039
- assert_equal "goood.png", @dummy.avatar.original_filename
1040
- end
1041
- end
1042
- end
1043
-
1044
- context "with specified cleaner" do
1045
- before do
1046
- @old_defaults = Paperclip::Attachment.default_options.dup
1047
- end
1048
-
1049
- after do
1050
- Paperclip::Attachment.default_options.merge! @old_defaults
1051
- end
1052
-
1053
- it "calls the given proc and take the result as cleaned filename" do
1054
- Paperclip::Attachment.default_options[:filename_cleaner] = lambda do |str|
1055
- "from_proc_#{str}"
1056
- end
1057
-
1058
- allow(@file).to receive(:original_filename).and_return("goood.png")
1059
- @dummy = Dummy.new
1060
- @dummy.avatar = @file
1061
- assert_equal "from_proc_goood.png", @dummy.avatar.original_filename
1062
- end
1063
-
1064
- it "calls the given object and take the result as the cleaned filename" do
1065
- class MyCleaner
1066
- def call(_filename)
1067
- "foo"
1068
- end
1069
- end
1070
- Paperclip::Attachment.default_options[:filename_cleaner] = MyCleaner.new
1071
-
1072
- allow(@file).to receive(:original_filename).and_return("goood.png")
1073
- @dummy = Dummy.new
1074
- @dummy.avatar = @file
1075
- assert_equal "foo", @dummy.avatar.original_filename
1076
- end
1077
- end
1078
- end
1079
-
1080
- context "Attachment with uppercase extension and a default style" do
1081
- before do
1082
- @old_defaults = Paperclip::Attachment.default_options.dup
1083
- Paperclip::Attachment.default_options.merge!(
1084
- path: ":rails_root/:attachment/:class/:style/:id/:basename.:extension"
1085
- )
1086
- FileUtils.rm_rf("tmp")
1087
- rebuild_model styles: { large: ["400x400", :jpg],
1088
- medium: ["100x100", :jpg],
1089
- small: ["32x32#", :jpg] },
1090
- default_style: :small
1091
- @instance = Dummy.new
1092
- allow(@instance).to receive(:id).and_return 123
1093
- @file = File.new(fixture_file("uppercase.PNG"), "rb")
1094
-
1095
- @attachment = @instance.avatar
1096
-
1097
- now = Time.now
1098
- allow(Time).to receive(:now).and_return(now)
1099
- @attachment.assign(@file)
1100
- @attachment.save
1101
- end
1102
-
1103
- after do
1104
- @file.close
1105
- Paperclip::Attachment.default_options.merge!(@old_defaults)
1106
- end
1107
-
1108
- it "has matching to_s and url methods" do
1109
- assert_equal @attachment.to_s, @attachment.url
1110
- assert_equal @attachment.to_s(:small), @attachment.url(:small)
1111
- end
1112
-
1113
- it "has matching expiring_url and url methods when using the filesystem storage" do
1114
- assert_equal @attachment.expiring_url, @attachment.url
1115
- end
1116
- end
1117
-
1118
- context "An attachment" do
1119
- before do
1120
- @old_defaults = Paperclip::Attachment.default_options.dup
1121
- Paperclip::Attachment.default_options.merge!(
1122
- path: ":rails_root/:attachment/:class/:style/:id/:basename.:extension"
1123
- )
1124
- FileUtils.rm_rf("tmp")
1125
- rebuild_model
1126
- @instance = Dummy.new
1127
- allow(@instance).to receive(:id).and_return 123
1128
- # @attachment = Paperclip::Attachment.new(:avatar, @instance)
1129
- @attachment = @instance.avatar
1130
- @file = File.new(fixture_file("5k.png"), "rb")
1131
- end
1132
-
1133
- after do
1134
- @file.close
1135
- Paperclip::Attachment.default_options.merge!(@old_defaults)
1136
- end
1137
-
1138
- it "raises if there are not the correct columns when you try to assign" do
1139
- @other_attachment = Paperclip::Attachment.new(:not_here, @instance)
1140
- assert_raises(Paperclip::Error) do
1141
- @other_attachment.assign(@file)
1142
- end
1143
- end
1144
-
1145
- it "clears out the previous assignment when assigned nil" do
1146
- @attachment.assign(@file)
1147
- @attachment.queued_for_write[:original]
1148
- @attachment.assign(nil)
1149
- assert_nil @attachment.queued_for_write[:original]
1150
- end
1151
-
1152
- it "does not do anything when it is assigned an empty string" do
1153
- @attachment.assign(@file)
1154
- original_file = @attachment.queued_for_write[:original]
1155
- @attachment.assign("")
1156
- assert_equal original_file, @attachment.queued_for_write[:original]
1157
- end
1158
-
1159
- it "returns nil as path when no file assigned" do
1160
- assert_equal nil, @attachment.path
1161
- assert_equal nil, @attachment.path(:blah)
1162
- end
1163
-
1164
- context "with a file assigned but not saved yet" do
1165
- it "clears out any attached files" do
1166
- @attachment.assign(@file)
1167
- assert @attachment.queued_for_write.present?
1168
- @attachment.clear
1169
- assert @attachment.queued_for_write.blank?
1170
- end
1171
- end
1172
-
1173
- context "with a file assigned in the database" do
1174
- before do
1175
- allow(@attachment).to receive(:instance_read).with(:file_name).and_return("5k.png")
1176
- allow(@attachment).to receive(:instance_read).with(:content_type).and_return("image/png")
1177
- allow(@attachment).to receive(:instance_read).with(:file_size).and_return(12345)
1178
- dtnow = DateTime.now
1179
- @now = Time.now
1180
- allow(Time).to receive(:now).and_return(@now)
1181
- allow(@attachment).to receive(:instance_read).with(:updated_at).and_return(dtnow)
1182
- end
1183
-
1184
- it "returns the proper path when filename has a single .'s" do
1185
- assert_equal File.expand_path("tmp/avatars/dummies/original/#{@instance.id}/5k.png"), File.expand_path(@attachment.path)
1186
- end
1187
-
1188
- it "returns the proper path when filename has multiple .'s" do
1189
- allow(@attachment).to receive(:instance_read).with(:file_name).and_return("5k.old.png")
1190
- assert_equal File.expand_path("tmp/avatars/dummies/original/#{@instance.id}/5k.old.png"), File.expand_path(@attachment.path)
1191
- end
1192
-
1193
- context "when expecting three styles" do
1194
- before do
1195
- rebuild_class styles: {
1196
- large: ["400x400", :png],
1197
- medium: ["100x100", :gif],
1198
- small: ["32x32#", :jpg]
1199
- }
1200
- @instance = Dummy.new
1201
- allow(@instance).to receive(:id).and_return 123
1202
- @file = File.new(fixture_file("5k.png"), "rb")
1203
- @attachment = @instance.avatar
1204
- end
1205
-
1206
- context "and assigned a file" do
1207
- before do
1208
- now = Time.now
1209
- allow(Time).to receive(:now).and_return(now)
1210
- @attachment.assign(@file)
1211
- end
1212
-
1213
- it "is dirty" do
1214
- assert @attachment.dirty?
1215
- end
1216
-
1217
- context "and saved" do
1218
- before do
1219
- @attachment.save
1220
- end
1221
-
1222
- it "commits the files to disk" do
1223
- [:large, :medium, :small].each do |style|
1224
- expect(@attachment.path(style)).to exist
1225
- end
1226
- end
1227
-
1228
- it "saves the files as the right formats and sizes" do
1229
- [[:large, 400, 61, "PNG"],
1230
- [:medium, 100, 15, "GIF"],
1231
- [:small, 32, 32, "JPEG"]].each do |style|
1232
- cmd = %[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"]
1233
- out = `#{cmd}`
1234
- width, height, _size, format = out.split(" ")
1235
- assert_equal style[1].to_s, width.to_s
1236
- assert_equal style[2].to_s, height.to_s
1237
- assert_equal style[3].to_s, format.to_s
1238
- end
1239
- end
1240
-
1241
- context "and trying to delete" do
1242
- before do
1243
- @existing_names = @attachment.styles.keys.map do |style|
1244
- @attachment.path(style)
1245
- end
1246
- end
1247
-
1248
- it "deletes the files after assigning nil" do
1249
- expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1250
- expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1251
- expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1252
- expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1253
- expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1254
- @attachment.assign nil
1255
- @attachment.save
1256
- @existing_names.each { |f| assert_file_not_exists(f) }
1257
- end
1258
-
1259
- it "deletes the files when you call #clear and #save" do
1260
- expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1261
- expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1262
- expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1263
- expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1264
- expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1265
- @attachment.clear
1266
- @attachment.save
1267
- @existing_names.each { |f| assert_file_not_exists(f) }
1268
- end
1269
-
1270
- it "deletes the files when you call #delete" do
1271
- expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1272
- expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1273
- expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1274
- expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1275
- expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1276
- @attachment.destroy
1277
- @existing_names.each { |f| assert_file_not_exists(f) }
1278
- end
1279
-
1280
- context "when keeping old files" do
1281
- before do
1282
- @attachment.options[:keep_old_files] = true
1283
- end
1284
-
1285
- it "keeps the files after assigning nil" do
1286
- expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1287
- expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1288
- expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1289
- expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1290
- expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1291
- @attachment.assign nil
1292
- @attachment.save
1293
- @existing_names.each { |f| assert_file_exists(f) }
1294
- end
1295
-
1296
- it "keeps the files when you call #clear and #save" do
1297
- expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1298
- expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1299
- expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1300
- expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1301
- expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1302
- @attachment.clear
1303
- @attachment.save
1304
- @existing_names.each { |f| assert_file_exists(f) }
1305
- end
1306
-
1307
- it "keeps the files when you call #delete" do
1308
- expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1309
- expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1310
- expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1311
- expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1312
- expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1313
- @attachment.destroy
1314
- @existing_names.each { |f| assert_file_exists(f) }
1315
- end
1316
- end
1317
- end
1318
- end
1319
- end
1320
- end
1321
- end
1322
-
1323
- context "when trying a nonexistant storage type" do
1324
- before do
1325
- rebuild_model storage: :not_here
1326
- end
1327
-
1328
- it "is not able to find the module" do
1329
- assert_raises(Paperclip::Errors::StorageMethodNotFound) { Dummy.new.avatar }
1330
- end
1331
- end
1332
- end
1333
-
1334
- context "An attachment with only a avatar_file_name column" do
1335
- before do
1336
- ActiveRecord::Migration.create_table :dummies, force: true do |table|
1337
- table.column :avatar_file_name, :string
1338
- end
1339
- rebuild_class
1340
- @dummy = Dummy.new
1341
- @file = File.new(fixture_file("5k.png"), "rb")
1342
- end
1343
-
1344
- after { @file.close }
1345
-
1346
- it "does not error when assigned an attachment" do
1347
- assert_nothing_raised { @dummy.avatar = @file }
1348
- end
1349
-
1350
- it "does not return the time when sent #avatar_updated_at" do
1351
- @dummy.avatar = @file
1352
- assert_nil @dummy.avatar.updated_at
1353
- end
1354
-
1355
- it "returns the right value when sent #avatar_file_size" do
1356
- @dummy.avatar = @file
1357
- assert_equal File.size(@file), @dummy.avatar.size
1358
- end
1359
-
1360
- context "and avatar_created_at column" do
1361
- before do
1362
- ActiveRecord::Migration.add_column :dummies, :avatar_created_at, :timestamp
1363
- rebuild_class
1364
- @dummy = Dummy.new
1365
- end
1366
-
1367
- it "does not error when assigned an attachment" do
1368
- assert_nothing_raised { @dummy.avatar = @file }
1369
- end
1370
-
1371
- it "returns the creation time when sent #avatar_created_at" do
1372
- now = Time.now
1373
- allow(Time).to receive(:now).and_return(now)
1374
- @dummy.avatar = @file
1375
- assert_equal now.to_i, @dummy.avatar.created_at
1376
- end
1377
-
1378
- it "returns the creation time when sent #avatar_created_at and the entry has been updated" do
1379
- creation = 2.hours.ago
1380
- now = Time.now
1381
- allow(Time).to receive(:now).and_return(creation)
1382
- @dummy.avatar = @file
1383
- allow(Time).to receive(:now).and_return(now)
1384
- @dummy.avatar = @file
1385
- assert_equal creation.to_i, @dummy.avatar.created_at
1386
- assert_not_equal now.to_i, @dummy.avatar.created_at
1387
- end
1388
-
1389
- it "sets changed? to true on attachment assignment" do
1390
- @dummy.avatar = @file
1391
- @dummy.save!
1392
- @dummy.avatar = @file
1393
- assert @dummy.changed?
1394
- end
1395
- end
1396
-
1397
- context "and avatar_updated_at column" do
1398
- before do
1399
- ActiveRecord::Migration.add_column :dummies, :avatar_updated_at, :timestamp
1400
- rebuild_class
1401
- @dummy = Dummy.new
1402
- end
1403
-
1404
- it "does not error when assigned an attachment" do
1405
- assert_nothing_raised { @dummy.avatar = @file }
1406
- end
1407
-
1408
- it "returns the right value when sent #avatar_updated_at" do
1409
- now = Time.now
1410
- allow(Time).to receive(:now).and_return(now)
1411
- @dummy.avatar = @file
1412
- assert_equal now.to_i, @dummy.avatar.updated_at
1413
- end
1414
- end
1415
-
1416
- it "does not calculate fingerprint" do
1417
- allow(Digest::MD5).to receive(:file)
1418
- @dummy.avatar = @file
1419
- expect(Digest::MD5).not_to have_received(:file)
1420
- end
1421
-
1422
- it "does not assign fingerprint" do
1423
- @dummy.avatar = @file
1424
- assert_nil @dummy.avatar.fingerprint
1425
- end
1426
-
1427
- context "and avatar_content_type column" do
1428
- before do
1429
- ActiveRecord::Migration.add_column :dummies, :avatar_content_type, :string
1430
- rebuild_class
1431
- @dummy = Dummy.new
1432
- end
1433
-
1434
- it "does not error when assigned an attachment" do
1435
- assert_nothing_raised { @dummy.avatar = @file }
1436
- end
1437
-
1438
- it "returns the right value when sent #avatar_content_type" do
1439
- @dummy.avatar = @file
1440
- assert_equal "image/png", @dummy.avatar.content_type
1441
- end
1442
- end
1443
-
1444
- context "and avatar_file_size column" do
1445
- before do
1446
- ActiveRecord::Migration.add_column :dummies, :avatar_file_size, :bigint
1447
- rebuild_class
1448
- @dummy = Dummy.new
1449
- end
1450
-
1451
- it "does not error when assigned an attachment" do
1452
- assert_nothing_raised { @dummy.avatar = @file }
1453
- end
1454
-
1455
- it "returns the right value when sent #avatar_file_size" do
1456
- @dummy.avatar = @file
1457
- assert_equal File.size(@file), @dummy.avatar.size
1458
- end
1459
-
1460
- it "returns the right value when saved, reloaded, and sent #avatar_file_size" do
1461
- @dummy.avatar = @file
1462
- @dummy.save
1463
- @dummy = Dummy.find(@dummy.id)
1464
- assert_equal File.size(@file), @dummy.avatar.size
1465
- end
1466
- end
1467
-
1468
- context "and avatar_fingerprint column" do
1469
- before do
1470
- ActiveRecord::Migration.add_column :dummies, :avatar_fingerprint, :string
1471
- rebuild_class
1472
- @dummy = Dummy.new
1473
- end
1474
-
1475
- it "does not error when assigned an attachment" do
1476
- assert_nothing_raised { @dummy.avatar = @file }
1477
- end
1478
-
1479
- context "with explicitly set digest" do
1480
- before do
1481
- rebuild_class adapter_options: { hash_digest: Digest::SHA256 }
1482
- @dummy = Dummy.new
1483
- end
1484
-
1485
- it "returns the right value when sent #avatar_fingerprint" do
1486
- @dummy.avatar = @file
1487
- assert_equal "734016d801a497f5579cdd4ef2ae1d020088c1db754dc434482d76dd5486520a",
1488
- @dummy.avatar_fingerprint
1489
- end
1490
-
1491
- it "returns the right value when saved, reloaded, and sent #avatar_fingerprint" do
1492
- @dummy.avatar = @file
1493
- @dummy.save
1494
- @dummy = Dummy.find(@dummy.id)
1495
- assert_equal "734016d801a497f5579cdd4ef2ae1d020088c1db754dc434482d76dd5486520a",
1496
- @dummy.avatar_fingerprint
1497
- end
1498
- end
1499
-
1500
- context "with the default digest" do
1501
- before do
1502
- rebuild_class # MD5 is the default
1503
- @dummy = Dummy.new
1504
- end
1505
-
1506
- it "returns the right value when sent #avatar_fingerprint" do
1507
- @dummy.avatar = @file
1508
- assert_equal "aec488126c3b33c08a10c3fa303acf27",
1509
- @dummy.avatar_fingerprint
1510
- end
1511
-
1512
- it "returns the right value when saved, reloaded, and sent #avatar_fingerprint" do
1513
- @dummy.avatar = @file
1514
- @dummy.save
1515
- @dummy = Dummy.find(@dummy.id)
1516
- assert_equal "aec488126c3b33c08a10c3fa303acf27",
1517
- @dummy.avatar_fingerprint
1518
- end
1519
- end
1520
- end
1521
- end
1522
-
1523
- context "an attachment with delete_file option set to false" do
1524
- before do
1525
- rebuild_model preserve_files: true
1526
- @dummy = Dummy.new
1527
- @file = File.new(fixture_file("5k.png"), "rb")
1528
- @dummy.avatar = @file
1529
- @dummy.save!
1530
- @attachment = @dummy.avatar
1531
- @path = @attachment.path
1532
- end
1533
-
1534
- after { @file.close }
1535
-
1536
- it "does not delete the files from storage when attachment is destroyed" do
1537
- @attachment.destroy
1538
- assert_file_exists(@path)
1539
- end
1540
-
1541
- it "clears out attachment data when attachment is destroyed" do
1542
- @attachment.destroy
1543
- assert !@attachment.exists?
1544
- assert_nil @dummy.avatar_file_name
1545
- end
1546
-
1547
- it "does not delete the file when model is destroyed" do
1548
- @dummy.destroy
1549
- assert_file_exists(@path)
1550
- end
1551
- end
1552
-
1553
- context "An attached file" do
1554
- before do
1555
- rebuild_model
1556
- @dummy = Dummy.new
1557
- @file = File.new(fixture_file("5k.png"), "rb")
1558
- @dummy.avatar = @file
1559
- @dummy.save!
1560
- @attachment = @dummy.avatar
1561
- @path = @attachment.path
1562
- end
1563
-
1564
- after { @file.close }
1565
-
1566
- it "is not deleted when the model fails to destroy" do
1567
- allow(@dummy).to receive(:destroy).and_raise(Exception)
1568
-
1569
- assert_raises Exception do
1570
- @dummy.destroy
1571
- end
1572
-
1573
- assert_file_exists(@path)
1574
- end
1575
-
1576
- it "is deleted when the model is destroyed" do
1577
- @dummy.destroy
1578
- assert_file_not_exists(@path)
1579
- end
1580
-
1581
- it "is not deleted when transaction rollbacks after model is destroyed" do
1582
- ActiveRecord::Base.transaction do
1583
- @dummy.destroy
1584
- raise ActiveRecord::Rollback
1585
- end
1586
-
1587
- assert_file_exists(@path)
1588
- end
1589
- end
1590
- end