kt-paperclip 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +17 -0
  3. data/.github/issue_template.md +3 -0
  4. data/.gitignore +19 -0
  5. data/.hound.yml +1050 -0
  6. data/.rubocop.yml +1 -0
  7. data/.travis.yml +47 -0
  8. data/Appraisals +24 -0
  9. data/CONTRIBUTING.md +86 -0
  10. data/Gemfile +18 -0
  11. data/LICENSE +24 -0
  12. data/NEWS +515 -0
  13. data/README.md +1053 -0
  14. data/RELEASING.md +17 -0
  15. data/Rakefile +52 -0
  16. data/UPGRADING +17 -0
  17. data/features/basic_integration.feature +85 -0
  18. data/features/migration.feature +29 -0
  19. data/features/rake_tasks.feature +62 -0
  20. data/features/step_definitions/attachment_steps.rb +110 -0
  21. data/features/step_definitions/html_steps.rb +15 -0
  22. data/features/step_definitions/rails_steps.rb +257 -0
  23. data/features/step_definitions/s3_steps.rb +14 -0
  24. data/features/step_definitions/web_steps.rb +106 -0
  25. data/features/support/env.rb +12 -0
  26. data/features/support/fakeweb.rb +11 -0
  27. data/features/support/file_helpers.rb +34 -0
  28. data/features/support/fixtures/boot_config.txt +15 -0
  29. data/features/support/fixtures/gemfile.txt +5 -0
  30. data/features/support/fixtures/preinitializer.txt +20 -0
  31. data/features/support/paths.rb +28 -0
  32. data/features/support/rails.rb +39 -0
  33. data/features/support/selectors.rb +19 -0
  34. data/gemfiles/4.2.gemfile +20 -0
  35. data/gemfiles/5.0.gemfile +20 -0
  36. data/gemfiles/5.1.gemfile +20 -0
  37. data/gemfiles/5.2.gemfile +20 -0
  38. data/gemfiles/6.0.gemfile +20 -0
  39. data/lib/generators/paperclip/USAGE +8 -0
  40. data/lib/generators/paperclip/paperclip_generator.rb +36 -0
  41. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
  42. data/lib/paperclip.rb +215 -0
  43. data/lib/paperclip/attachment.rb +617 -0
  44. data/lib/paperclip/attachment_registry.rb +60 -0
  45. data/lib/paperclip/callbacks.rb +42 -0
  46. data/lib/paperclip/content_type_detector.rb +80 -0
  47. data/lib/paperclip/errors.rb +34 -0
  48. data/lib/paperclip/file_command_content_type_detector.rb +28 -0
  49. data/lib/paperclip/filename_cleaner.rb +15 -0
  50. data/lib/paperclip/geometry.rb +157 -0
  51. data/lib/paperclip/geometry_detector_factory.rb +45 -0
  52. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  53. data/lib/paperclip/glue.rb +17 -0
  54. data/lib/paperclip/has_attached_file.rb +116 -0
  55. data/lib/paperclip/helpers.rb +60 -0
  56. data/lib/paperclip/interpolations.rb +201 -0
  57. data/lib/paperclip/interpolations/plural_cache.rb +18 -0
  58. data/lib/paperclip/io_adapters/abstract_adapter.rb +75 -0
  59. data/lib/paperclip/io_adapters/attachment_adapter.rb +47 -0
  60. data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
  61. data/lib/paperclip/io_adapters/empty_string_adapter.rb +19 -0
  62. data/lib/paperclip/io_adapters/file_adapter.rb +26 -0
  63. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +16 -0
  64. data/lib/paperclip/io_adapters/identity_adapter.rb +17 -0
  65. data/lib/paperclip/io_adapters/nil_adapter.rb +37 -0
  66. data/lib/paperclip/io_adapters/registry.rb +36 -0
  67. data/lib/paperclip/io_adapters/stringio_adapter.rb +36 -0
  68. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +44 -0
  69. data/lib/paperclip/io_adapters/uri_adapter.rb +68 -0
  70. data/lib/paperclip/locales/en.yml +18 -0
  71. data/lib/paperclip/logger.rb +21 -0
  72. data/lib/paperclip/matchers.rb +64 -0
  73. data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
  74. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +101 -0
  75. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
  76. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +97 -0
  77. data/lib/paperclip/media_type_spoof_detector.rb +90 -0
  78. data/lib/paperclip/missing_attachment_styles.rb +84 -0
  79. data/lib/paperclip/processor.rb +56 -0
  80. data/lib/paperclip/processor_helpers.rb +52 -0
  81. data/lib/paperclip/rails_environment.rb +21 -0
  82. data/lib/paperclip/railtie.rb +31 -0
  83. data/lib/paperclip/schema.rb +81 -0
  84. data/lib/paperclip/storage.rb +3 -0
  85. data/lib/paperclip/storage/filesystem.rb +99 -0
  86. data/lib/paperclip/storage/fog.rb +252 -0
  87. data/lib/paperclip/storage/s3.rb +461 -0
  88. data/lib/paperclip/style.rb +106 -0
  89. data/lib/paperclip/tempfile.rb +42 -0
  90. data/lib/paperclip/tempfile_factory.rb +22 -0
  91. data/lib/paperclip/thumbnail.rb +131 -0
  92. data/lib/paperclip/url_generator.rb +76 -0
  93. data/lib/paperclip/validators.rb +73 -0
  94. data/lib/paperclip/validators/attachment_content_type_validator.rb +88 -0
  95. data/lib/paperclip/validators/attachment_file_name_validator.rb +75 -0
  96. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +28 -0
  97. data/lib/paperclip/validators/attachment_presence_validator.rb +28 -0
  98. data/lib/paperclip/validators/attachment_size_validator.rb +109 -0
  99. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +29 -0
  100. data/lib/paperclip/version.rb +3 -0
  101. data/lib/tasks/paperclip.rake +140 -0
  102. data/paperclip.gemspec +50 -0
  103. data/shoulda_macros/paperclip.rb +134 -0
  104. data/spec/database.yml +4 -0
  105. data/spec/paperclip/attachment_definitions_spec.rb +13 -0
  106. data/spec/paperclip/attachment_processing_spec.rb +79 -0
  107. data/spec/paperclip/attachment_registry_spec.rb +158 -0
  108. data/spec/paperclip/attachment_spec.rb +1590 -0
  109. data/spec/paperclip/content_type_detector_spec.rb +47 -0
  110. data/spec/paperclip/file_command_content_type_detector_spec.rb +40 -0
  111. data/spec/paperclip/filename_cleaner_spec.rb +13 -0
  112. data/spec/paperclip/geometry_detector_spec.rb +38 -0
  113. data/spec/paperclip/geometry_parser_spec.rb +73 -0
  114. data/spec/paperclip/geometry_spec.rb +255 -0
  115. data/spec/paperclip/glue_spec.rb +42 -0
  116. data/spec/paperclip/has_attached_file_spec.rb +78 -0
  117. data/spec/paperclip/integration_spec.rb +702 -0
  118. data/spec/paperclip/interpolations_spec.rb +270 -0
  119. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +160 -0
  120. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +140 -0
  121. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +88 -0
  122. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
  123. data/spec/paperclip/io_adapters/file_adapter_spec.rb +131 -0
  124. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +137 -0
  125. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
  126. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
  127. data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
  128. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
  129. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
  130. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +221 -0
  131. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
  132. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +108 -0
  133. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
  134. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
  135. data/spec/paperclip/media_type_spoof_detector_spec.rb +120 -0
  136. data/spec/paperclip/meta_class_spec.rb +30 -0
  137. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +88 -0
  138. data/spec/paperclip/paperclip_spec.rb +196 -0
  139. data/spec/paperclip/plural_cache_spec.rb +37 -0
  140. data/spec/paperclip/processor_helpers_spec.rb +57 -0
  141. data/spec/paperclip/processor_spec.rb +26 -0
  142. data/spec/paperclip/rails_environment_spec.rb +30 -0
  143. data/spec/paperclip/rake_spec.rb +103 -0
  144. data/spec/paperclip/schema_spec.rb +252 -0
  145. data/spec/paperclip/storage/filesystem_spec.rb +79 -0
  146. data/spec/paperclip/storage/fog_spec.rb +560 -0
  147. data/spec/paperclip/storage/s3_live_spec.rb +188 -0
  148. data/spec/paperclip/storage/s3_spec.rb +1695 -0
  149. data/spec/paperclip/style_spec.rb +251 -0
  150. data/spec/paperclip/tempfile_factory_spec.rb +33 -0
  151. data/spec/paperclip/tempfile_spec.rb +35 -0
  152. data/spec/paperclip/thumbnail_spec.rb +504 -0
  153. data/spec/paperclip/url_generator_spec.rb +221 -0
  154. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
  155. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +159 -0
  156. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
  157. data/spec/paperclip/validators/attachment_size_validator_spec.rb +235 -0
  158. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +48 -0
  159. data/spec/paperclip/validators_spec.rb +164 -0
  160. data/spec/spec_helper.rb +45 -0
  161. data/spec/support/assertions.rb +84 -0
  162. data/spec/support/fake_model.rb +24 -0
  163. data/spec/support/fake_rails.rb +12 -0
  164. data/spec/support/fixtures/12k.png +0 -0
  165. data/spec/support/fixtures/50x50.png +0 -0
  166. data/spec/support/fixtures/5k.png +0 -0
  167. data/spec/support/fixtures/animated +0 -0
  168. data/spec/support/fixtures/animated.gif +0 -0
  169. data/spec/support/fixtures/animated.unknown +0 -0
  170. data/spec/support/fixtures/bad.png +1 -0
  171. data/spec/support/fixtures/empty.html +1 -0
  172. data/spec/support/fixtures/empty.xlsx +0 -0
  173. data/spec/support/fixtures/fog.yml +8 -0
  174. data/spec/support/fixtures/rotated.jpg +0 -0
  175. data/spec/support/fixtures/s3.yml +8 -0
  176. data/spec/support/fixtures/spaced file.jpg +0 -0
  177. data/spec/support/fixtures/spaced file.png +0 -0
  178. data/spec/support/fixtures/text.txt +1 -0
  179. data/spec/support/fixtures/twopage.pdf +0 -0
  180. data/spec/support/fixtures/uppercase.PNG +0 -0
  181. data/spec/support/matchers/accept.rb +5 -0
  182. data/spec/support/matchers/exist.rb +5 -0
  183. data/spec/support/matchers/have_column.rb +23 -0
  184. data/spec/support/mock_attachment.rb +24 -0
  185. data/spec/support/mock_interpolator.rb +24 -0
  186. data/spec/support/mock_url_generator_builder.rb +26 -0
  187. data/spec/support/model_reconstruction.rb +72 -0
  188. data/spec/support/reporting.rb +11 -0
  189. data/spec/support/test_data.rb +13 -0
  190. data/spec/support/version_helper.rb +9 -0
  191. metadata +586 -0
@@ -0,0 +1,270 @@
1
+ require "spec_helper"
2
+
3
+ describe Paperclip::Interpolations do
4
+ it "returns all methods but the infrastructure when sent #all" do
5
+ methods = Paperclip::Interpolations.all
6
+ assert !methods.include?(:[])
7
+ assert !methods.include?(:[]=)
8
+ assert !methods.include?(:all)
9
+ methods.each do |m|
10
+ assert Paperclip::Interpolations.respond_to?(m)
11
+ end
12
+ end
13
+
14
+ it "returns the Rails.root" do
15
+ assert_equal Rails.root, Paperclip::Interpolations.rails_root(:attachment, :style)
16
+ end
17
+
18
+ it "returns the Rails.env" do
19
+ assert_equal Rails.env, Paperclip::Interpolations.rails_env(:attachment, :style)
20
+ end
21
+
22
+ it "returns the class of the Interpolations module when called with no params" do
23
+ assert_equal Module, Paperclip::Interpolations.class
24
+ end
25
+
26
+ it "returns the class of the instance" do
27
+ class Thing; end
28
+ attachment = spy
29
+ expect(attachment).to receive(:instance).and_return(attachment)
30
+ expect(attachment).to receive(:class).and_return(Thing)
31
+ assert_equal "things", Paperclip::Interpolations.class(attachment, :style)
32
+ end
33
+
34
+ it "returns the basename of the file" do
35
+ attachment = spy
36
+ expect(attachment).to receive(:original_filename).and_return("one.jpg")
37
+ assert_equal "one", Paperclip::Interpolations.basename(attachment, :style)
38
+ end
39
+
40
+ it "returns the extension of the file" do
41
+ attachment = spy
42
+ expect(attachment).to receive(:original_filename).and_return("one.jpg")
43
+ expect(attachment).to receive(:styles).and_return({})
44
+ assert_equal "jpg", Paperclip::Interpolations.extension(attachment, :style)
45
+ end
46
+
47
+ it "returns the extension of the file as the format if defined in the style" do
48
+ attachment = spy
49
+ expect(attachment).to_not receive(:original_filename)
50
+ expect(attachment).to receive(:styles).at_least(2).times.and_return(style: { format: "png" })
51
+
52
+ [:style, "style"].each do |style|
53
+ assert_equal "png", Paperclip::Interpolations.extension(attachment, style)
54
+ end
55
+ end
56
+
57
+ it "returns the extension of the file based on the content type" do
58
+ attachment = spy
59
+ expect(attachment).to receive(:content_type).and_return("image/png")
60
+ expect(attachment).to receive(:styles).and_return({})
61
+ interpolations = Paperclip::Interpolations
62
+ expect(interpolations).to receive(:extension).and_return("random")
63
+ assert_equal "png", interpolations.content_type_extension(attachment, :style)
64
+ end
65
+
66
+ it "returns the original extension of the file if it matches a content type extension" do
67
+ attachment = spy
68
+ expect(attachment).to receive(:content_type).and_return("image/jpeg")
69
+ expect(attachment).to receive(:styles).and_return({})
70
+ interpolations = Paperclip::Interpolations
71
+ expect(interpolations).to receive(:extension).and_return("jpe")
72
+ assert_equal "jpe", interpolations.content_type_extension(attachment, :style)
73
+ end
74
+
75
+ it "returns the extension of the file with a dot" do
76
+ attachment = spy
77
+ expect(attachment).to receive(:original_filename).and_return("one.jpg")
78
+ expect(attachment).to receive(:styles).and_return({})
79
+ assert_equal ".jpg", Paperclip::Interpolations.dotextension(attachment, :style)
80
+ end
81
+
82
+ it "returns the extension of the file without a dot if the extension is empty" do
83
+ attachment = spy
84
+ expect(attachment).to receive(:original_filename).and_return("one")
85
+ expect(attachment).to receive(:styles).and_return({})
86
+ assert_equal "", Paperclip::Interpolations.dotextension(attachment, :style)
87
+ end
88
+
89
+ it "returns the latter half of the content type of the extension if no match found" do
90
+ attachment = spy
91
+ allow(attachment).to receive(:content_type).at_least(1).times.and_return("not/found")
92
+ allow(attachment).to receive(:styles).and_return({})
93
+ interpolations = Paperclip::Interpolations
94
+ expect(interpolations).to receive(:extension).and_return("random")
95
+ assert_equal "found", interpolations.content_type_extension(attachment, :style)
96
+ end
97
+
98
+ it "returns the format if defined in the style, ignoring the content type" do
99
+ attachment = spy
100
+ expect(attachment).to receive(:content_type).and_return("image/jpeg")
101
+ expect(attachment).to receive(:styles).and_return(style: { format: "png" })
102
+ interpolations = Paperclip::Interpolations
103
+ expect(interpolations).to receive(:extension).and_return("random")
104
+ assert_equal "png", interpolations.content_type_extension(attachment, :style)
105
+ end
106
+
107
+ it "is able to handle numeric style names" do
108
+ attachment = spy(
109
+ styles: {:"4" => {format: :expected_extension}}
110
+ )
111
+ assert_equal :expected_extension, Paperclip::Interpolations.extension(attachment, 4)
112
+ end
113
+
114
+ it "returns the #to_param of the attachment" do
115
+ attachment = spy
116
+ expect(attachment).to receive(:to_param).and_return("23-awesome")
117
+ expect(attachment).to receive(:instance).and_return(attachment)
118
+ assert_equal "23-awesome", Paperclip::Interpolations.param(attachment, :style)
119
+ end
120
+
121
+ it "returns the id of the attachment" do
122
+ attachment = spy
123
+ expect(attachment).to receive(:id).and_return(23)
124
+ expect(attachment).to receive(:instance).and_return(attachment)
125
+ assert_equal 23, Paperclip::Interpolations.id(attachment, :style)
126
+ end
127
+
128
+ it "returns nil for attachments to new records" do
129
+ attachment = spy
130
+ expect(attachment).to receive(:id).and_return(nil)
131
+ expect(attachment).to receive(:instance).and_return(attachment)
132
+ assert_nil Paperclip::Interpolations.id(attachment, :style)
133
+ end
134
+
135
+ it "returns the partitioned id of the attachment when the id is an integer" do
136
+ attachment = spy
137
+ expect(attachment).to receive(:id).and_return(23)
138
+ expect(attachment).to receive(:instance).and_return(attachment)
139
+ assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style)
140
+ end
141
+
142
+ it "returns the partitioned id when the id is above 999_999_999" do
143
+ attachment = spy
144
+ expect(attachment).to receive(:id).and_return(Paperclip::Interpolations::ID_PARTITION_LIMIT)
145
+ expect(attachment).to receive(:instance).and_return(attachment)
146
+ assert_equal "001/000/000/000",
147
+ Paperclip::Interpolations.id_partition(attachment, :style)
148
+ end
149
+
150
+ it "returns the partitioned id of the attachment when the id is a string" do
151
+ attachment = spy
152
+ expect(attachment).to receive(:id).and_return("32fnj23oio2f")
153
+ expect(attachment).to receive(:instance).and_return(attachment)
154
+ assert_equal "32f/nj2/3oi", Paperclip::Interpolations.id_partition(attachment, :style)
155
+ end
156
+
157
+ it "returns nil for the partitioned id of an attachment to a new record (when the id is nil)" do
158
+ attachment = spy
159
+ expect(attachment).to receive(:id).and_return(nil)
160
+ expect(attachment).to receive(:instance).and_return(attachment)
161
+ assert_nil Paperclip::Interpolations.id_partition(attachment, :style)
162
+ end
163
+
164
+ it "returns the name of the attachment" do
165
+ attachment = spy
166
+ expect(attachment).to receive(:name).and_return("file")
167
+ assert_equal "files", Paperclip::Interpolations.attachment(attachment, :style)
168
+ end
169
+
170
+ it "returns the style" do
171
+ assert_equal :style, Paperclip::Interpolations.style(:attachment, :style)
172
+ end
173
+
174
+ it "returns the default style" do
175
+ attachment = spy
176
+ expect(attachment).to receive(:default_style).and_return(:default_style)
177
+ assert_equal :default_style, Paperclip::Interpolations.style(attachment, nil)
178
+ end
179
+
180
+ it "reinterpolates :url" do
181
+ attachment = spy
182
+ expect(attachment).to receive(:url).with(:style, timestamp: false, escape: false).and_return("1234")
183
+ assert_equal "1234", Paperclip::Interpolations.url(attachment, :style)
184
+ end
185
+
186
+ it "raises if infinite loop detcted reinterpolating :url" do
187
+ attachment = Object.new
188
+ class << attachment
189
+ def url(*_args)
190
+ Paperclip::Interpolations.url(self, :style)
191
+ end
192
+ end
193
+ assert_raises(Paperclip::Errors::InfiniteInterpolationError) { Paperclip::Interpolations.url(attachment, :style) }
194
+ end
195
+
196
+ it "returns the filename as basename.extension" do
197
+ attachment = spy
198
+ expect(attachment).to receive(:styles).and_return({})
199
+ expect(attachment).to receive(:original_filename).and_return("one.jpg").twice
200
+ assert_equal "one.jpg", Paperclip::Interpolations.filename(attachment, :style)
201
+ end
202
+
203
+ it "returns the filename as basename.extension when format supplied" do
204
+ attachment = spy
205
+ expect(attachment).to receive(:styles).and_return(style: { format: :png })
206
+ expect(attachment).to receive(:original_filename).and_return("one.jpg").once
207
+ assert_equal "one.png", Paperclip::Interpolations.filename(attachment, :style)
208
+ end
209
+
210
+ it "returns the filename as basename when extension is blank" do
211
+ attachment = spy
212
+ allow(attachment).to receive(:styles).and_return({})
213
+ allow(attachment).to receive(:original_filename).and_return("one")
214
+ assert_equal "one", Paperclip::Interpolations.filename(attachment, :style)
215
+ end
216
+
217
+ it "returns the basename when the extension contains regexp special characters" do
218
+ attachment = spy
219
+ allow(attachment).to receive(:styles).and_return({})
220
+ allow(attachment).to receive(:original_filename).and_return("one.ab)")
221
+ assert_equal "one", Paperclip::Interpolations.basename(attachment, :style)
222
+ end
223
+
224
+ it "returns the timestamp" do
225
+ now = Time.now
226
+ zone = "UTC"
227
+ attachment = spy
228
+ expect(attachment).to receive(:instance_read).with(:updated_at).and_return(now)
229
+ expect(attachment).to receive(:time_zone).and_return(zone)
230
+ assert_equal now.in_time_zone(zone).to_s, Paperclip::Interpolations.timestamp(attachment, :style)
231
+ end
232
+
233
+ it "returns updated_at" do
234
+ attachment = spy
235
+ seconds_since_epoch = 1234567890
236
+ expect(attachment).to receive(:updated_at).and_return(seconds_since_epoch)
237
+ assert_equal seconds_since_epoch, Paperclip::Interpolations.updated_at(attachment, :style)
238
+ end
239
+
240
+ it "returns attachment's hash when passing both arguments" do
241
+ attachment = spy
242
+ fake_hash = "a_wicked_secure_hash"
243
+ expect(attachment).to receive(:hash_key).and_return(fake_hash)
244
+ assert_equal fake_hash, Paperclip::Interpolations.hash(attachment, :style)
245
+ end
246
+
247
+ it "returns Object#hash when passing no argument" do
248
+ attachment = spy
249
+ fake_hash = "a_wicked_secure_hash"
250
+ expect(attachment).to_not receive(:hash_key)
251
+ assert_not_equal fake_hash, Paperclip::Interpolations.hash
252
+ end
253
+
254
+ it "calls all expected interpolations with the given arguments" do
255
+ expect(Paperclip::Interpolations).to receive(:id).with(:attachment, :style).and_return(1234)
256
+ expect(Paperclip::Interpolations).to receive(:attachment).with(:attachment, :style).and_return("attachments")
257
+ expect(Paperclip::Interpolations).to_not receive(:notreal)
258
+ value = Paperclip::Interpolations.interpolate(":notreal/:id/:attachment", :attachment, :style)
259
+ assert_equal ":notreal/1234/attachments", value
260
+ end
261
+
262
+ it "handles question marks" do
263
+ Paperclip.interpolates :foo? do
264
+ "bar"
265
+ end
266
+ expect(Paperclip::Interpolations).to_not receive(:fool)
267
+ value = Paperclip::Interpolations.interpolate(":fo/:foo?")
268
+ assert_equal ":fo/bar", value
269
+ end
270
+ end
@@ -0,0 +1,160 @@
1
+ require "spec_helper"
2
+
3
+ describe Paperclip::AbstractAdapter do
4
+ class TestAdapter < Paperclip::AbstractAdapter
5
+ attr_accessor :tempfile
6
+
7
+ def content_type
8
+ Paperclip::ContentTypeDetector.new(path).detect
9
+ end
10
+ end
11
+
12
+ subject { TestAdapter.new(nil) }
13
+
14
+ context "content type from file contents" do
15
+ before do
16
+ allow(subject).to receive(:path).and_return("image.png")
17
+ allow(Paperclip).to receive(:run).and_return("image/png\n")
18
+ allow_any_instance_of(Paperclip::ContentTypeDetector).to receive(:type_from_mime_magic).and_return("image/png")
19
+ end
20
+
21
+ it "returns the content type without newline" do
22
+ assert_equal "image/png", subject.content_type
23
+ end
24
+ end
25
+
26
+ context "nil?" do
27
+ it "returns false" do
28
+ assert !subject.nil?
29
+ end
30
+ end
31
+
32
+ context "delegation" do
33
+ before do
34
+ subject.tempfile = double("Tempfile")
35
+ end
36
+
37
+ [:binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :readbyte, :rewind, :unlink].each do |method|
38
+ it "delegates #{method} to @tempfile" do
39
+ allow(subject.tempfile).to receive(method)
40
+ subject.public_send(method)
41
+ expect(subject.tempfile).to have_received(method)
42
+ end
43
+ end
44
+ end
45
+
46
+ it "gets rid of slashes and colons in filenames" do
47
+ subject.original_filename = "awesome/file:name.png"
48
+
49
+ assert_equal "awesome_file_name.png", subject.original_filename
50
+ end
51
+
52
+ it "is an assignment" do
53
+ assert subject.assignment?
54
+ end
55
+
56
+ it "is not nil" do
57
+ assert !subject.nil?
58
+ end
59
+
60
+ it "generates a destination filename with no original filename" do
61
+ expect(subject.send(:destination).path).to_not be_nil
62
+ end
63
+
64
+ it "uses the original filename to generate the tempfile" do
65
+ subject.original_filename = "file.png"
66
+ expect(subject.send(:destination).path).to end_with(".png")
67
+ end
68
+
69
+ context "generates a fingerprint" do
70
+ subject { TestAdapter.new(nil, options) }
71
+
72
+ before do
73
+ allow(subject).to receive(:path).and_return(fixture_file("50x50.png"))
74
+ end
75
+
76
+ context "MD5" do
77
+ let(:options) { { hash_digest: Digest::MD5 } }
78
+
79
+ it "returns a fingerprint" do
80
+ expect(subject.fingerprint).to be_a String
81
+ expect(subject.fingerprint).to eq "a790b00c9b5d58a8fd17a1ec5a187129"
82
+ end
83
+ end
84
+
85
+ context "SHA256" do
86
+ let(:options) { { hash_digest: Digest::SHA256 } }
87
+
88
+ it "returns a fingerprint" do
89
+ expect(subject.fingerprint).to be_a String
90
+ expect(subject.fingerprint).
91
+ to eq "243d7ce1099719df25f600f1c369c629fb979f88d5a01dbe7d0d48c8e6715bb1"
92
+ end
93
+ end
94
+ end
95
+
96
+ context "#copy_to_tempfile" do
97
+ around do |example|
98
+ FileUtils.module_eval do
99
+ class << self
100
+ alias paperclip_ln ln
101
+
102
+ def ln(*)
103
+ raise Errno::EXDEV
104
+ end
105
+ end
106
+ end
107
+
108
+ example.run
109
+
110
+ FileUtils.module_eval do
111
+ class << self
112
+ alias ln paperclip_ln
113
+ undef paperclip_ln
114
+ end
115
+ end
116
+ end
117
+
118
+ it "should return a readable file even when linking fails" do
119
+ src = open(fixture_file("5k.png"), "rb")
120
+ expect(subject.send(:copy_to_tempfile, src).read).to eq src.read
121
+ end
122
+ end
123
+
124
+ context "#original_filename=" do
125
+ it "should not fail with a nil original filename" do
126
+ expect { subject.original_filename = nil }.not_to raise_error
127
+ end
128
+ end
129
+
130
+ context "#link_or_copy_file" do
131
+ class TestLinkOrCopyAdapter < Paperclip::AbstractAdapter
132
+ public :copy_to_tempfile, :destination
133
+ end
134
+
135
+ subject { TestLinkOrCopyAdapter.new(nil) }
136
+ let(:body) { "body" }
137
+
138
+ let(:file) do
139
+ t = Tempfile.new("destination")
140
+ t.print(body)
141
+ t.rewind
142
+ t
143
+ end
144
+
145
+ after do
146
+ file.close
147
+ file.unlink
148
+ end
149
+
150
+ it "should be able to read the file" do
151
+ expect(subject.copy_to_tempfile(file).read).to eq(body)
152
+ end
153
+
154
+ it "should be able to reopen the file after symlink has failed" do
155
+ expect(FileUtils).to receive(:ln).and_raise(Errno::EXDEV)
156
+
157
+ expect(subject.copy_to_tempfile(file).read).to eq(body)
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,140 @@
1
+ require "spec_helper"
2
+
3
+ describe Paperclip::AttachmentAdapter do
4
+ before do
5
+ rebuild_model path: "tmp/:class/:attachment/:style/:filename", styles: { thumb: "50x50" }
6
+ @attachment = Dummy.new.avatar
7
+ end
8
+
9
+ context "for an attachment" do
10
+ before do
11
+ @file = File.new(fixture_file("5k.png"))
12
+ @file.binmode
13
+
14
+ @attachment.assign(@file)
15
+ @attachment.save
16
+ @subject = Paperclip.io_adapters.for(@attachment,
17
+ hash_digest: Digest::MD5)
18
+ end
19
+
20
+ after do
21
+ @file.close
22
+ @subject.close
23
+ end
24
+
25
+ it "gets the right filename" do
26
+ assert_equal "5k.png", @subject.original_filename
27
+ end
28
+
29
+ it "forces binmode on tempfile" do
30
+ assert @subject.instance_variable_get("@tempfile").binmode?
31
+ end
32
+
33
+ it "gets the content type" do
34
+ assert_equal "image/png", @subject.content_type
35
+ end
36
+
37
+ it "gets the file's size" do
38
+ assert_equal 4456, @subject.size
39
+ end
40
+
41
+ it "returns false for a call to nil?" do
42
+ assert !@subject.nil?
43
+ end
44
+
45
+ it "generates a MD5 hash of the contents" do
46
+ expected = Digest::MD5.file(@file.path).to_s
47
+ assert_equal expected, @subject.fingerprint
48
+ end
49
+
50
+ it "reads the contents of the file" do
51
+ expected = @file.read
52
+ actual = @subject.read
53
+ assert !expected.empty?
54
+ assert_equal expected.length, actual.length
55
+ assert_equal expected, actual
56
+ end
57
+ end
58
+
59
+ context "for a file with restricted characters in the name" do
60
+ before do
61
+ file_contents = IO.read(fixture_file("animated.gif"))
62
+ @file = StringIO.new(file_contents)
63
+ allow(@file).to receive(:original_filename).and_return("image:restricted.gif")
64
+ @file.binmode
65
+
66
+ @attachment.assign(@file)
67
+ @attachment.save
68
+ @subject = Paperclip.io_adapters.for(@attachment,
69
+ hash_digest: Digest::MD5)
70
+ end
71
+
72
+ after do
73
+ @subject.close
74
+ end
75
+
76
+ it "does not generate paths that include restricted characters" do
77
+ expect(@subject.path).to_not match(/:/)
78
+ end
79
+
80
+ it "does not generate filenames that include restricted characters" do
81
+ assert_equal "image_restricted.gif", @subject.original_filename
82
+ end
83
+ end
84
+
85
+ context "for a style" do
86
+ before do
87
+ @file = File.new(fixture_file("5k.png"))
88
+ @file.binmode
89
+
90
+ @attachment.assign(@file)
91
+
92
+ @thumb = Tempfile.new("thumbnail").tap(&:binmode)
93
+ FileUtils.cp @attachment.queued_for_write[:thumb].path, @thumb.path
94
+
95
+ @attachment.save
96
+ @subject = Paperclip.io_adapters.for(@attachment.styles[:thumb],
97
+ hash_digest: Digest::MD5)
98
+ end
99
+
100
+ after do
101
+ @file.close
102
+ @thumb.close
103
+ @subject.close
104
+ end
105
+
106
+ it "gets the original filename" do
107
+ assert_equal "5k.png", @subject.original_filename
108
+ end
109
+
110
+ it "forces binmode on tempfile" do
111
+ assert @subject.instance_variable_get("@tempfile").binmode?
112
+ end
113
+
114
+ it "gets the content type" do
115
+ assert_equal "image/png", @subject.content_type
116
+ end
117
+
118
+ it "gets the thumbnail's file size" do
119
+ assert_equal @thumb.size, @subject.size
120
+ end
121
+
122
+ it "returns false for a call to nil?" do
123
+ assert !@subject.nil?
124
+ end
125
+
126
+ it "generates a MD5 hash of the contents" do
127
+ expected = Digest::MD5.file(@thumb.path).to_s
128
+ assert_equal expected, @subject.fingerprint
129
+ end
130
+
131
+ it "reads the contents of the thumbnail" do
132
+ @thumb.rewind
133
+ expected = @thumb.read
134
+ actual = @subject.read
135
+ assert !expected.empty?
136
+ assert_equal expected.length, actual.length
137
+ assert_equal expected, actual
138
+ end
139
+ end
140
+ end