jr-paperclip 7.3.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 (200) hide show
  1. checksums.yaml +7 -0
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  4. data/.github/ISSUE_TEMPLATE/custom.md +10 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. data/.github/workflows/reviewdog.yml +23 -0
  7. data/.github/workflows/test.yml +46 -0
  8. data/.gitignore +19 -0
  9. data/.qlty/.gitignore +7 -0
  10. data/.qlty/qlty.toml +89 -0
  11. data/.rubocop.yml +1060 -0
  12. data/Appraisals +29 -0
  13. data/CONTRIBUTING.md +85 -0
  14. data/Gemfile +17 -0
  15. data/LICENSE +25 -0
  16. data/NEWS +567 -0
  17. data/README.md +1083 -0
  18. data/RELEASING.md +17 -0
  19. data/Rakefile +52 -0
  20. data/bin/console +11 -0
  21. data/features/basic_integration.feature +85 -0
  22. data/features/migration.feature +29 -0
  23. data/features/rake_tasks.feature +62 -0
  24. data/features/step_definitions/attachment_steps.rb +121 -0
  25. data/features/step_definitions/html_steps.rb +15 -0
  26. data/features/step_definitions/rails_steps.rb +271 -0
  27. data/features/step_definitions/s3_steps.rb +16 -0
  28. data/features/step_definitions/web_steps.rb +106 -0
  29. data/features/support/env.rb +12 -0
  30. data/features/support/file_helpers.rb +34 -0
  31. data/features/support/fixtures/boot_config.txt +15 -0
  32. data/features/support/fixtures/gemfile.txt +5 -0
  33. data/features/support/fixtures/preinitializer.txt +20 -0
  34. data/features/support/paths.rb +28 -0
  35. data/features/support/rails.rb +39 -0
  36. data/features/support/selectors.rb +19 -0
  37. data/features/support/webmock_setup.rb +8 -0
  38. data/gemfiles/7.0.gemfile +20 -0
  39. data/gemfiles/7.1.gemfile +20 -0
  40. data/gemfiles/7.2.gemfile +20 -0
  41. data/gemfiles/8.0.gemfile +20 -0
  42. data/gemfiles/8.1.gemfile +20 -0
  43. data/lib/generators/paperclip/USAGE +8 -0
  44. data/lib/generators/paperclip/paperclip_generator.rb +36 -0
  45. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
  46. data/lib/jr-paperclip.rb +1 -0
  47. data/lib/paperclip/attachment.rb +634 -0
  48. data/lib/paperclip/attachment_registry.rb +60 -0
  49. data/lib/paperclip/callbacks.rb +42 -0
  50. data/lib/paperclip/content_type_detector.rb +85 -0
  51. data/lib/paperclip/errors.rb +34 -0
  52. data/lib/paperclip/file_command_content_type_detector.rb +28 -0
  53. data/lib/paperclip/filename_cleaner.rb +15 -0
  54. data/lib/paperclip/geometry.rb +157 -0
  55. data/lib/paperclip/geometry_detector_factory.rb +45 -0
  56. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  57. data/lib/paperclip/glue.rb +18 -0
  58. data/lib/paperclip/has_attached_file.rb +116 -0
  59. data/lib/paperclip/helpers.rb +60 -0
  60. data/lib/paperclip/interpolations/plural_cache.rb +18 -0
  61. data/lib/paperclip/interpolations.rb +205 -0
  62. data/lib/paperclip/io_adapters/abstract_adapter.rb +75 -0
  63. data/lib/paperclip/io_adapters/attachment_adapter.rb +56 -0
  64. data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
  65. data/lib/paperclip/io_adapters/empty_string_adapter.rb +19 -0
  66. data/lib/paperclip/io_adapters/file_adapter.rb +26 -0
  67. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +16 -0
  68. data/lib/paperclip/io_adapters/identity_adapter.rb +17 -0
  69. data/lib/paperclip/io_adapters/nil_adapter.rb +37 -0
  70. data/lib/paperclip/io_adapters/registry.rb +36 -0
  71. data/lib/paperclip/io_adapters/stringio_adapter.rb +36 -0
  72. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +44 -0
  73. data/lib/paperclip/io_adapters/uri_adapter.rb +78 -0
  74. data/lib/paperclip/locales/en.yml +18 -0
  75. data/lib/paperclip/locales/fr.yml +18 -0
  76. data/lib/paperclip/locales/gd.yml +20 -0
  77. data/lib/paperclip/logger.rb +21 -0
  78. data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
  79. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +101 -0
  80. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
  81. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +97 -0
  82. data/lib/paperclip/matchers.rb +64 -0
  83. data/lib/paperclip/media_type_spoof_detector.rb +93 -0
  84. data/lib/paperclip/missing_attachment_styles.rb +84 -0
  85. data/lib/paperclip/processor.rb +56 -0
  86. data/lib/paperclip/processor_helpers.rb +52 -0
  87. data/lib/paperclip/rails_environment.rb +21 -0
  88. data/lib/paperclip/railtie.rb +31 -0
  89. data/lib/paperclip/schema.rb +104 -0
  90. data/lib/paperclip/storage/filesystem.rb +99 -0
  91. data/lib/paperclip/storage/fog.rb +262 -0
  92. data/lib/paperclip/storage/s3.rb +497 -0
  93. data/lib/paperclip/storage.rb +3 -0
  94. data/lib/paperclip/style.rb +106 -0
  95. data/lib/paperclip/tempfile.rb +42 -0
  96. data/lib/paperclip/tempfile_factory.rb +22 -0
  97. data/lib/paperclip/thumbnail.rb +131 -0
  98. data/lib/paperclip/url_generator.rb +83 -0
  99. data/lib/paperclip/validators/attachment_content_type_validator.rb +95 -0
  100. data/lib/paperclip/validators/attachment_file_name_validator.rb +82 -0
  101. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +28 -0
  102. data/lib/paperclip/validators/attachment_presence_validator.rb +28 -0
  103. data/lib/paperclip/validators/attachment_size_validator.rb +126 -0
  104. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +29 -0
  105. data/lib/paperclip/validators.rb +73 -0
  106. data/lib/paperclip/version.rb +3 -0
  107. data/lib/paperclip.rb +215 -0
  108. data/lib/tasks/paperclip.rake +140 -0
  109. data/paperclip.gemspec +51 -0
  110. data/shoulda_macros/paperclip.rb +134 -0
  111. data/spec/database.yml +4 -0
  112. data/spec/paperclip/attachment_definitions_spec.rb +13 -0
  113. data/spec/paperclip/attachment_processing_spec.rb +79 -0
  114. data/spec/paperclip/attachment_registry_spec.rb +158 -0
  115. data/spec/paperclip/attachment_spec.rb +1617 -0
  116. data/spec/paperclip/content_type_detector_spec.rb +58 -0
  117. data/spec/paperclip/file_command_content_type_detector_spec.rb +40 -0
  118. data/spec/paperclip/filename_cleaner_spec.rb +13 -0
  119. data/spec/paperclip/geometry_detector_spec.rb +47 -0
  120. data/spec/paperclip/geometry_parser_spec.rb +73 -0
  121. data/spec/paperclip/geometry_spec.rb +267 -0
  122. data/spec/paperclip/glue_spec.rb +63 -0
  123. data/spec/paperclip/has_attached_file_spec.rb +78 -0
  124. data/spec/paperclip/integration_spec.rb +702 -0
  125. data/spec/paperclip/interpolations_spec.rb +270 -0
  126. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +160 -0
  127. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +167 -0
  128. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +88 -0
  129. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
  130. data/spec/paperclip/io_adapters/file_adapter_spec.rb +134 -0
  131. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +142 -0
  132. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
  133. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
  134. data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
  135. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
  136. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
  137. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +231 -0
  138. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
  139. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +108 -0
  140. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
  141. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
  142. data/spec/paperclip/media_type_spoof_detector_spec.rb +126 -0
  143. data/spec/paperclip/meta_class_spec.rb +30 -0
  144. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +88 -0
  145. data/spec/paperclip/paperclip_spec.rb +196 -0
  146. data/spec/paperclip/plural_cache_spec.rb +37 -0
  147. data/spec/paperclip/processor_helpers_spec.rb +57 -0
  148. data/spec/paperclip/processor_spec.rb +26 -0
  149. data/spec/paperclip/rails_environment_spec.rb +30 -0
  150. data/spec/paperclip/rake_spec.rb +103 -0
  151. data/spec/paperclip/schema_spec.rb +298 -0
  152. data/spec/paperclip/storage/filesystem_spec.rb +102 -0
  153. data/spec/paperclip/storage/fog_spec.rb +606 -0
  154. data/spec/paperclip/storage/s3_live_spec.rb +188 -0
  155. data/spec/paperclip/storage/s3_spec.rb +1974 -0
  156. data/spec/paperclip/style_spec.rb +251 -0
  157. data/spec/paperclip/tempfile_factory_spec.rb +33 -0
  158. data/spec/paperclip/tempfile_spec.rb +35 -0
  159. data/spec/paperclip/thumbnail_spec.rb +504 -0
  160. data/spec/paperclip/url_generator_spec.rb +231 -0
  161. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +410 -0
  162. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +249 -0
  163. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
  164. data/spec/paperclip/validators/attachment_size_validator_spec.rb +325 -0
  165. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +48 -0
  166. data/spec/paperclip/validators_spec.rb +179 -0
  167. data/spec/spec_helper.rb +52 -0
  168. data/spec/support/assertions.rb +84 -0
  169. data/spec/support/fake_model.rb +24 -0
  170. data/spec/support/fake_rails.rb +12 -0
  171. data/spec/support/fixtures/12k.png +0 -0
  172. data/spec/support/fixtures/50x50.png +0 -0
  173. data/spec/support/fixtures/5k.png +0 -0
  174. data/spec/support/fixtures/animated +0 -0
  175. data/spec/support/fixtures/animated.gif +0 -0
  176. data/spec/support/fixtures/animated.unknown +0 -0
  177. data/spec/support/fixtures/aws_s3.yml +13 -0
  178. data/spec/support/fixtures/bad.png +1 -0
  179. data/spec/support/fixtures/empty.html +1 -0
  180. data/spec/support/fixtures/empty.xlsx +0 -0
  181. data/spec/support/fixtures/fog.yml +8 -0
  182. data/spec/support/fixtures/rotated.jpg +0 -0
  183. data/spec/support/fixtures/s3.yml +8 -0
  184. data/spec/support/fixtures/sample.xlsm +0 -0
  185. data/spec/support/fixtures/spaced file.jpg +0 -0
  186. data/spec/support/fixtures/spaced file.png +0 -0
  187. data/spec/support/fixtures/text.txt +1 -0
  188. data/spec/support/fixtures/twopage.pdf +0 -0
  189. data/spec/support/fixtures/uppercase.PNG +0 -0
  190. data/spec/support/matchers/accept.rb +5 -0
  191. data/spec/support/matchers/exist.rb +5 -0
  192. data/spec/support/matchers/have_column.rb +23 -0
  193. data/spec/support/mock_attachment.rb +24 -0
  194. data/spec/support/mock_interpolator.rb +24 -0
  195. data/spec/support/mock_url_generator_builder.rb +26 -0
  196. data/spec/support/model_reconstruction.rb +72 -0
  197. data/spec/support/reporting.rb +11 -0
  198. data/spec/support/test_data.rb +13 -0
  199. data/spec/support/version_helper.rb +9 -0
  200. metadata +702 -0
@@ -0,0 +1,1617 @@
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
+ @file = File.new(fixture_file("5k.png"), "rb")
1202
+ @attachment = @instance.avatar
1203
+ end
1204
+
1205
+ context "and assigned a file" do
1206
+ before do
1207
+ now = Time.now
1208
+ allow(Time).to receive(:now).and_return(now)
1209
+ @attachment.assign(@file)
1210
+ end
1211
+
1212
+ it "is dirty" do
1213
+ assert @attachment.dirty?
1214
+ end
1215
+
1216
+ context "and saved" do
1217
+ before do
1218
+ # Save the model to properly test after_commit callbacks
1219
+ @instance.save!
1220
+ @attachment = @instance.avatar
1221
+ end
1222
+
1223
+ it "commits the files to disk" do
1224
+ [:large, :medium, :small].each do |style|
1225
+ expect(@attachment.path(style)).to exist
1226
+ end
1227
+ end
1228
+
1229
+ it "saves the files as the right formats and sizes" do
1230
+ [[:large, 400, 61, "PNG"],
1231
+ [:medium, 100, 15, "GIF"],
1232
+ [:small, 32, 32, "JPEG"]].each do |style|
1233
+ cmd = %[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"]
1234
+ out = `#{cmd}`
1235
+ width, height, _size, format = out.split(" ")
1236
+ assert_equal style[1].to_s, width.to_s
1237
+ assert_equal style[2].to_s, height.to_s
1238
+ assert_equal style[3].to_s, format.to_s
1239
+ end
1240
+ end
1241
+
1242
+ context "and trying to delete" do
1243
+ before do
1244
+ @existing_names = @attachment.styles.keys.map do |style|
1245
+ @attachment.path(style)
1246
+ end
1247
+ end
1248
+
1249
+ it "deletes the files after assigning nil" do
1250
+ expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1251
+ expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1252
+ expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1253
+ expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1254
+ expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1255
+ @attachment.assign nil
1256
+ @attachment.save
1257
+ @existing_names.each { |f| assert_file_not_exists(f) }
1258
+ end
1259
+
1260
+ it "deletes the files when you call #clear and #save" do
1261
+ expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1262
+ expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1263
+ expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1264
+ expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1265
+ expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1266
+ @attachment.clear
1267
+ @attachment.save
1268
+ @existing_names.each { |f| assert_file_not_exists(f) }
1269
+ end
1270
+
1271
+ it "deletes the files when you call #destroy" do
1272
+ expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1273
+ expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1274
+ expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1275
+ expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1276
+ expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1277
+ @attachment.destroy
1278
+ @existing_names.each { |f| assert_file_not_exists(f) }
1279
+ end
1280
+
1281
+ it "deletes the files when you destroy the model" do
1282
+ expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1283
+ expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1284
+ expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1285
+ expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1286
+ expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1287
+ @attachment.instance.destroy
1288
+ @existing_names.each { |f| assert_file_not_exists(f) }
1289
+ end
1290
+
1291
+ context "when 'return_file_attributes_on_destroy' option is set to true" do
1292
+ before do
1293
+ @attachment.options[:return_file_attributes_on_destroy] = true
1294
+ end
1295
+
1296
+ it "does not override attachment-related attributes and deletes the files" do
1297
+ expect(@attachment).not_to receive(:instance_write)
1298
+ expect(@attachment).not_to receive(:instance_write)
1299
+ expect(@attachment).not_to receive(:instance_write)
1300
+ expect(@attachment).not_to receive(:instance_write)
1301
+ expect(@attachment).not_to receive(:instance_write)
1302
+ @attachment.instance.destroy
1303
+ @existing_names.each { |f| assert_file_not_exists(f) }
1304
+ end
1305
+ end
1306
+
1307
+ context "when keeping old files" do
1308
+ before do
1309
+ @attachment.options[:keep_old_files] = true
1310
+ end
1311
+
1312
+ it "keeps the files after assigning nil" do
1313
+ expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1314
+ expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1315
+ expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1316
+ expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1317
+ expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1318
+ @attachment.assign nil
1319
+ @attachment.save
1320
+ @existing_names.each { |f| assert_file_exists(f) }
1321
+ end
1322
+
1323
+ it "keeps the files when you call #clear and #save" do
1324
+ expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1325
+ expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1326
+ expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1327
+ expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1328
+ expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1329
+ @attachment.clear
1330
+ @attachment.save
1331
+ @existing_names.each { |f| assert_file_exists(f) }
1332
+ end
1333
+
1334
+ it "keeps the files when you call #destroy" do
1335
+ expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1336
+ expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1337
+ expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1338
+ expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1339
+ expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1340
+ @attachment.destroy
1341
+ @existing_names.each { |f| assert_file_exists(f) }
1342
+ end
1343
+ end
1344
+ end
1345
+ end
1346
+ end
1347
+ end
1348
+ end
1349
+
1350
+ context "when trying a nonexistant storage type" do
1351
+ before do
1352
+ rebuild_model storage: :not_here
1353
+ end
1354
+
1355
+ it "is not able to find the module" do
1356
+ assert_raises(Paperclip::Errors::StorageMethodNotFound) { Dummy.new.avatar }
1357
+ end
1358
+ end
1359
+ end
1360
+
1361
+ context "An attachment with only a avatar_file_name column" do
1362
+ before do
1363
+ ActiveRecord::Migration.create_table :dummies, force: true do |table|
1364
+ table.column :avatar_file_name, :string
1365
+ end
1366
+ rebuild_class
1367
+ @dummy = Dummy.new
1368
+ @file = File.new(fixture_file("5k.png"), "rb")
1369
+ end
1370
+
1371
+ after { @file.close }
1372
+
1373
+ it "does not error when assigned an attachment" do
1374
+ assert_nothing_raised { @dummy.avatar = @file }
1375
+ end
1376
+
1377
+ it "does not return the time when sent #avatar_updated_at" do
1378
+ @dummy.avatar = @file
1379
+ assert_nil @dummy.avatar.updated_at
1380
+ end
1381
+
1382
+ it "returns the right value when sent #avatar_file_size" do
1383
+ @dummy.avatar = @file
1384
+ assert_equal File.size(@file), @dummy.avatar.size
1385
+ end
1386
+
1387
+ context "and avatar_created_at column" do
1388
+ before do
1389
+ ActiveRecord::Migration.add_column :dummies, :avatar_created_at, :timestamp
1390
+ rebuild_class
1391
+ @dummy = Dummy.new
1392
+ end
1393
+
1394
+ it "does not error when assigned an attachment" do
1395
+ assert_nothing_raised { @dummy.avatar = @file }
1396
+ end
1397
+
1398
+ it "returns the creation time when sent #avatar_created_at" do
1399
+ now = Time.now
1400
+ allow(Time).to receive(:now).and_return(now)
1401
+ @dummy.avatar = @file
1402
+ assert_equal now.to_i, @dummy.avatar.created_at
1403
+ end
1404
+
1405
+ it "returns the creation time when sent #avatar_created_at and the entry has been updated" do
1406
+ creation = 2.hours.ago
1407
+ now = Time.now
1408
+ allow(Time).to receive(:now).and_return(creation)
1409
+ @dummy.avatar = @file
1410
+ allow(Time).to receive(:now).and_return(now)
1411
+ @dummy.avatar = @file
1412
+ assert_equal creation.to_i, @dummy.avatar.created_at
1413
+ assert_not_equal now.to_i, @dummy.avatar.created_at
1414
+ end
1415
+
1416
+ it "sets changed? to true on attachment assignment" do
1417
+ @dummy.avatar = @file
1418
+ @dummy.save!
1419
+ @dummy.avatar = @file
1420
+ assert @dummy.changed?
1421
+ end
1422
+ end
1423
+
1424
+ context "and avatar_updated_at column" do
1425
+ before do
1426
+ ActiveRecord::Migration.add_column :dummies, :avatar_updated_at, :timestamp
1427
+ rebuild_class
1428
+ @dummy = Dummy.new
1429
+ end
1430
+
1431
+ it "does not error when assigned an attachment" do
1432
+ assert_nothing_raised { @dummy.avatar = @file }
1433
+ end
1434
+
1435
+ it "returns the right value when sent #avatar_updated_at" do
1436
+ now = Time.now
1437
+ allow(Time).to receive(:now).and_return(now)
1438
+ @dummy.avatar = @file
1439
+ assert_equal now.to_i, @dummy.avatar.updated_at
1440
+ end
1441
+ end
1442
+
1443
+ it "does not calculate fingerprint" do
1444
+ allow(Digest::MD5).to receive(:file)
1445
+ @dummy.avatar = @file
1446
+ expect(Digest::MD5).not_to have_received(:file)
1447
+ end
1448
+
1449
+ it "does not assign fingerprint" do
1450
+ @dummy.avatar = @file
1451
+ assert_nil @dummy.avatar.fingerprint
1452
+ end
1453
+
1454
+ context "and avatar_content_type column" do
1455
+ before do
1456
+ ActiveRecord::Migration.add_column :dummies, :avatar_content_type, :string
1457
+ rebuild_class
1458
+ @dummy = Dummy.new
1459
+ end
1460
+
1461
+ it "does not error when assigned an attachment" do
1462
+ assert_nothing_raised { @dummy.avatar = @file }
1463
+ end
1464
+
1465
+ it "returns the right value when sent #avatar_content_type" do
1466
+ @dummy.avatar = @file
1467
+ assert_equal "image/png", @dummy.avatar.content_type
1468
+ end
1469
+ end
1470
+
1471
+ context "and avatar_file_size column" do
1472
+ before do
1473
+ ActiveRecord::Migration.add_column :dummies, :avatar_file_size, :bigint
1474
+ rebuild_class
1475
+ @dummy = Dummy.new
1476
+ end
1477
+
1478
+ it "does not error when assigned an attachment" do
1479
+ assert_nothing_raised { @dummy.avatar = @file }
1480
+ end
1481
+
1482
+ it "returns the right value when sent #avatar_file_size" do
1483
+ @dummy.avatar = @file
1484
+ assert_equal File.size(@file), @dummy.avatar.size
1485
+ end
1486
+
1487
+ it "returns the right value when saved, reloaded, and sent #avatar_file_size" do
1488
+ @dummy.avatar = @file
1489
+ @dummy.save
1490
+ @dummy = Dummy.find(@dummy.id)
1491
+ assert_equal File.size(@file), @dummy.avatar.size
1492
+ end
1493
+ end
1494
+
1495
+ context "and avatar_fingerprint column" do
1496
+ before do
1497
+ ActiveRecord::Migration.add_column :dummies, :avatar_fingerprint, :string
1498
+ rebuild_class
1499
+ @dummy = Dummy.new
1500
+ end
1501
+
1502
+ it "does not error when assigned an attachment" do
1503
+ assert_nothing_raised { @dummy.avatar = @file }
1504
+ end
1505
+
1506
+ context "with explicitly set digest" do
1507
+ before do
1508
+ rebuild_class adapter_options: { hash_digest: Digest::SHA256 }
1509
+ @dummy = Dummy.new
1510
+ end
1511
+
1512
+ it "returns the right value when sent #avatar_fingerprint" do
1513
+ @dummy.avatar = @file
1514
+ assert_equal "734016d801a497f5579cdd4ef2ae1d020088c1db754dc434482d76dd5486520a",
1515
+ @dummy.avatar_fingerprint
1516
+ end
1517
+
1518
+ it "returns the right value when saved, reloaded, and sent #avatar_fingerprint" do
1519
+ @dummy.avatar = @file
1520
+ @dummy.save
1521
+ @dummy = Dummy.find(@dummy.id)
1522
+ assert_equal "734016d801a497f5579cdd4ef2ae1d020088c1db754dc434482d76dd5486520a",
1523
+ @dummy.avatar_fingerprint
1524
+ end
1525
+ end
1526
+
1527
+ context "with the default digest" do
1528
+ before do
1529
+ rebuild_class # MD5 is the default
1530
+ @dummy = Dummy.new
1531
+ end
1532
+
1533
+ it "returns the right value when sent #avatar_fingerprint" do
1534
+ @dummy.avatar = @file
1535
+ assert_equal "aec488126c3b33c08a10c3fa303acf27",
1536
+ @dummy.avatar_fingerprint
1537
+ end
1538
+
1539
+ it "returns the right value when saved, reloaded, and sent #avatar_fingerprint" do
1540
+ @dummy.avatar = @file
1541
+ @dummy.save
1542
+ @dummy = Dummy.find(@dummy.id)
1543
+ assert_equal "aec488126c3b33c08a10c3fa303acf27",
1544
+ @dummy.avatar_fingerprint
1545
+ end
1546
+ end
1547
+ end
1548
+ end
1549
+
1550
+ context "an attachment with delete_file option set to false" do
1551
+ before do
1552
+ rebuild_model preserve_files: true
1553
+ @dummy = Dummy.new
1554
+ @file = File.new(fixture_file("5k.png"), "rb")
1555
+ @dummy.avatar = @file
1556
+ @dummy.save!
1557
+ @attachment = @dummy.avatar
1558
+ @path = @attachment.path
1559
+ end
1560
+
1561
+ after { @file.close }
1562
+
1563
+ it "does not delete the files from storage when attachment is destroyed" do
1564
+ @attachment.destroy
1565
+ assert_file_exists(@path)
1566
+ end
1567
+
1568
+ it "clears out attachment data when attachment is destroyed" do
1569
+ @attachment.destroy
1570
+ assert !@attachment.exists?
1571
+ assert_nil @dummy.avatar_file_name
1572
+ end
1573
+
1574
+ it "does not delete the file when model is destroyed" do
1575
+ @dummy.destroy
1576
+ assert_file_exists(@path)
1577
+ end
1578
+ end
1579
+
1580
+ context "An attached file" do
1581
+ before do
1582
+ rebuild_model
1583
+ @dummy = Dummy.new
1584
+ @file = File.new(fixture_file("5k.png"), "rb")
1585
+ @dummy.avatar = @file
1586
+ @dummy.save!
1587
+ @attachment = @dummy.avatar
1588
+ @path = @attachment.path
1589
+ end
1590
+
1591
+ after { @file.close }
1592
+
1593
+ it "is not deleted when the model fails to destroy" do
1594
+ allow(@dummy).to receive(:destroy).and_raise(Exception)
1595
+
1596
+ assert_raises Exception do
1597
+ @dummy.destroy
1598
+ end
1599
+
1600
+ assert_file_exists(@path)
1601
+ end
1602
+
1603
+ it "is deleted when the model is destroyed" do
1604
+ @dummy.destroy
1605
+ assert_file_not_exists(@path)
1606
+ end
1607
+
1608
+ it "is not deleted when transaction rollbacks after model is destroyed" do
1609
+ ActiveRecord::Base.transaction do
1610
+ @dummy.destroy
1611
+ raise ActiveRecord::Rollback
1612
+ end
1613
+
1614
+ assert_file_exists(@path)
1615
+ end
1616
+ end
1617
+ end