jr-paperclip 8.0.1 → 8.0.3

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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS +9 -0
  3. data/lib/paperclip/thumbnail.rb +18 -15
  4. data/lib/paperclip/version.rb +1 -1
  5. metadata +3 -245
  6. data/.github/FUNDING.yml +0 -3
  7. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -18
  8. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  9. data/.github/workflows/reviewdog.yml +0 -23
  10. data/.github/workflows/tests.yml +0 -56
  11. data/.gitignore +0 -19
  12. data/.qlty/.gitignore +0 -7
  13. data/.qlty/qlty.toml +0 -89
  14. data/Appraisals +0 -29
  15. data/Gemfile +0 -18
  16. data/bin/console +0 -11
  17. data/features/basic_integration.feature +0 -112
  18. data/features/migration.feature +0 -29
  19. data/features/rake_tasks.feature +0 -62
  20. data/features/step_definitions/attachment_steps.rb +0 -138
  21. data/features/step_definitions/html_steps.rb +0 -15
  22. data/features/step_definitions/rails_steps.rb +0 -271
  23. data/features/step_definitions/s3_steps.rb +0 -16
  24. data/features/step_definitions/web_steps.rb +0 -106
  25. data/features/support/env.rb +0 -12
  26. data/features/support/file_helpers.rb +0 -34
  27. data/features/support/fixtures/boot_config.txt +0 -15
  28. data/features/support/fixtures/gemfile.txt +0 -5
  29. data/features/support/fixtures/preinitializer.txt +0 -20
  30. data/features/support/paths.rb +0 -28
  31. data/features/support/rails.rb +0 -39
  32. data/features/support/selectors.rb +0 -19
  33. data/features/support/webmock_setup.rb +0 -8
  34. data/gemfiles/7.0.gemfile +0 -21
  35. data/gemfiles/7.1.gemfile +0 -21
  36. data/gemfiles/7.2.gemfile +0 -21
  37. data/gemfiles/8.0.gemfile +0 -21
  38. data/gemfiles/8.1.gemfile +0 -21
  39. data/paperclip.gemspec +0 -52
  40. data/spec/database.yml +0 -4
  41. data/spec/paperclip/attachment_definitions_spec.rb +0 -313
  42. data/spec/paperclip/attachment_processing_spec.rb +0 -79
  43. data/spec/paperclip/attachment_registry_spec.rb +0 -158
  44. data/spec/paperclip/attachment_spec.rb +0 -1617
  45. data/spec/paperclip/content_type_detector_spec.rb +0 -58
  46. data/spec/paperclip/file_command_content_type_detector_spec.rb +0 -40
  47. data/spec/paperclip/filename_cleaner_spec.rb +0 -13
  48. data/spec/paperclip/geometry_detector_spec.rb +0 -96
  49. data/spec/paperclip/geometry_parser_spec.rb +0 -73
  50. data/spec/paperclip/geometry_spec.rb +0 -270
  51. data/spec/paperclip/glue_spec.rb +0 -63
  52. data/spec/paperclip/has_attached_file_spec.rb +0 -78
  53. data/spec/paperclip/helpers_spec.rb +0 -49
  54. data/spec/paperclip/integration_spec.rb +0 -702
  55. data/spec/paperclip/interpolations_spec.rb +0 -270
  56. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +0 -160
  57. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +0 -167
  58. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +0 -88
  59. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +0 -17
  60. data/spec/paperclip/io_adapters/file_adapter_spec.rb +0 -134
  61. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +0 -142
  62. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +0 -8
  63. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +0 -25
  64. data/spec/paperclip/io_adapters/registry_spec.rb +0 -35
  65. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +0 -64
  66. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +0 -146
  67. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +0 -231
  68. data/spec/paperclip/lazy_thumbnail_compatibility_spec.rb +0 -266
  69. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +0 -19
  70. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +0 -108
  71. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +0 -69
  72. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +0 -88
  73. data/spec/paperclip/media_type_spoof_detector_spec.rb +0 -126
  74. data/spec/paperclip/meta_class_spec.rb +0 -30
  75. data/spec/paperclip/migration_guide_example_spec.rb +0 -44
  76. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +0 -88
  77. data/spec/paperclip/paperclip_spec.rb +0 -196
  78. data/spec/paperclip/plural_cache_spec.rb +0 -37
  79. data/spec/paperclip/processor_helpers_spec.rb +0 -57
  80. data/spec/paperclip/processor_spec.rb +0 -60
  81. data/spec/paperclip/rails_environment_spec.rb +0 -30
  82. data/spec/paperclip/rake_spec.rb +0 -103
  83. data/spec/paperclip/schema_spec.rb +0 -298
  84. data/spec/paperclip/storage/filesystem_spec.rb +0 -102
  85. data/spec/paperclip/storage/fog_spec.rb +0 -606
  86. data/spec/paperclip/storage/s3_live_spec.rb +0 -188
  87. data/spec/paperclip/storage/s3_spec.rb +0 -1974
  88. data/spec/paperclip/style_spec.rb +0 -309
  89. data/spec/paperclip/tempfile_factory_spec.rb +0 -33
  90. data/spec/paperclip/tempfile_spec.rb +0 -35
  91. data/spec/paperclip/thumbnail_custom_options_spec.rb +0 -225
  92. data/spec/paperclip/thumbnail_loader_options_spec.rb +0 -53
  93. data/spec/paperclip/thumbnail_security_spec.rb +0 -42
  94. data/spec/paperclip/thumbnail_spec.rb +0 -1460
  95. data/spec/paperclip/url_generator_spec.rb +0 -231
  96. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +0 -410
  97. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +0 -249
  98. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +0 -85
  99. data/spec/paperclip/validators/attachment_size_validator_spec.rb +0 -325
  100. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +0 -48
  101. data/spec/paperclip/validators_spec.rb +0 -179
  102. data/spec/spec_helper.rb +0 -52
  103. data/spec/support/assertions.rb +0 -84
  104. data/spec/support/fake_model.rb +0 -24
  105. data/spec/support/fake_rails.rb +0 -12
  106. data/spec/support/fixtures/12k.png +0 -0
  107. data/spec/support/fixtures/50x50.png +0 -0
  108. data/spec/support/fixtures/5k.png +0 -0
  109. data/spec/support/fixtures/animated +0 -0
  110. data/spec/support/fixtures/animated.gif +0 -0
  111. data/spec/support/fixtures/animated.unknown +0 -0
  112. data/spec/support/fixtures/aws_s3.yml +0 -13
  113. data/spec/support/fixtures/bad.png +0 -1
  114. data/spec/support/fixtures/empty.html +0 -1
  115. data/spec/support/fixtures/empty.xlsx +0 -0
  116. data/spec/support/fixtures/fog.yml +0 -8
  117. data/spec/support/fixtures/rotated.jpg +0 -0
  118. data/spec/support/fixtures/s3.yml +0 -8
  119. data/spec/support/fixtures/sample.xlsm +0 -0
  120. data/spec/support/fixtures/spaced file.jpg +0 -0
  121. data/spec/support/fixtures/spaced file.png +0 -0
  122. data/spec/support/fixtures/text.txt +0 -1
  123. data/spec/support/fixtures/twopage.pdf +0 -0
  124. data/spec/support/fixtures/uppercase.PNG +0 -0
  125. data/spec/support/matchers/accept.rb +0 -5
  126. data/spec/support/matchers/exist.rb +0 -5
  127. data/spec/support/matchers/have_column.rb +0 -23
  128. data/spec/support/mock_attachment.rb +0 -24
  129. data/spec/support/mock_interpolator.rb +0 -24
  130. data/spec/support/mock_url_generator_builder.rb +0 -26
  131. data/spec/support/model_reconstruction.rb +0 -72
  132. data/spec/support/reporting.rb +0 -11
  133. data/spec/support/test_data.rb +0 -13
  134. data/spec/support/version_helper.rb +0 -9
@@ -1,231 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Paperclip::UriAdapter do
4
- let(:content_type) { "image/png" }
5
- let(:meta) { {} }
6
-
7
- before do
8
- @open_return = StringIO.new("xxx")
9
- allow(@open_return).to receive(:content_type).and_return(content_type)
10
- allow(@open_return).to receive(:meta).and_return(meta)
11
- Paperclip::UriAdapter.register
12
- end
13
-
14
- after do
15
- Paperclip.io_adapters.unregister(described_class)
16
- end
17
-
18
- context "a new instance" do
19
- let(:meta) { { "content-type" => "image/png" } }
20
-
21
- before do
22
- allow_any_instance_of(Paperclip::UriAdapter).
23
- to receive(:download_content).and_return(@open_return)
24
-
25
- @uri = URI.parse("http://thoughtbot.com/images/thoughtbot-logo.png")
26
- @subject = Paperclip.io_adapters.for(@uri, hash_digest: Digest::MD5)
27
- end
28
-
29
- it "returns a file name" do
30
- assert_equal "thoughtbot-logo.png", @subject.original_filename
31
- end
32
-
33
- it "closes open handle after reading" do
34
- assert_equal true, @open_return.closed?
35
- end
36
-
37
- it "returns a content type" do
38
- assert_equal "image/png", @subject.content_type
39
- end
40
-
41
- it "returns the size of the data" do
42
- assert_equal @open_return.size, @subject.size
43
- end
44
-
45
- it "generates an MD5 hash of the contents" do
46
- assert_equal Digest::MD5.hexdigest("xxx"), @subject.fingerprint
47
- end
48
-
49
- it "generates correct fingerprint after read" do
50
- fingerprint = Digest::MD5.hexdigest(@subject.read)
51
- assert_equal fingerprint, @subject.fingerprint
52
- end
53
-
54
- it "generates same fingerprint" do
55
- assert_equal @subject.fingerprint, @subject.fingerprint
56
- end
57
-
58
- it "returns the data contained in the StringIO" do
59
- assert_equal "xxx", @subject.read
60
- end
61
-
62
- it "accepts a content_type" do
63
- @subject.content_type = "image/png"
64
- assert_equal "image/png", @subject.content_type
65
- end
66
-
67
- it "accepts an original_filename" do
68
- @subject.original_filename = "image.png"
69
- assert_equal "image.png", @subject.original_filename
70
- end
71
- end
72
-
73
- context "a directory index url" do
74
- let(:content_type) { "text/html" }
75
- let(:meta) { { "content-type" => "text/html" } }
76
-
77
- before do
78
- allow_any_instance_of(Paperclip::UriAdapter).
79
- to receive(:download_content).and_return(@open_return)
80
-
81
- @uri = URI.parse("http://thoughtbot.com")
82
- @subject = Paperclip.io_adapters.for(@uri)
83
- end
84
-
85
- it "returns a file name" do
86
- assert_equal "index.html", @subject.original_filename
87
- end
88
-
89
- it "returns a content type" do
90
- assert_equal "text/html", @subject.content_type
91
- end
92
- end
93
-
94
- context "a url with query params" do
95
- before do
96
- allow_any_instance_of(Paperclip::UriAdapter).
97
- to receive(:download_content).and_return(@open_return)
98
-
99
- @uri = URI.parse("https://github.com/thoughtbot/paperclip?file=test")
100
- @subject = Paperclip.io_adapters.for(@uri)
101
- end
102
-
103
- it "returns a file name" do
104
- assert_equal "paperclip", @subject.original_filename
105
- end
106
- end
107
-
108
- context "a url with content disposition headers" do
109
- let(:file_name) { "test_document.pdf" }
110
- let(:filename_from_path) { "paperclip" }
111
-
112
- before do
113
- allow_any_instance_of(Paperclip::UriAdapter).
114
- to receive(:download_content).and_return(@open_return)
115
-
116
- @uri = URI.parse(
117
- "https://github.com/thoughtbot/#{filename_from_path}?file=test"
118
- )
119
- end
120
-
121
- it "returns file name from path" do
122
- meta["content-disposition"] = "inline;"
123
-
124
- @subject = Paperclip.io_adapters.for(@uri)
125
-
126
- assert_equal filename_from_path, @subject.original_filename
127
- end
128
-
129
- it "returns a file name enclosed in double quotes" do
130
- file_name = "john's test document.pdf"
131
- meta["content-disposition"] = "attachment; filename=\"#{file_name}\";"
132
-
133
- @subject = Paperclip.io_adapters.for(@uri)
134
-
135
- assert_equal file_name, @subject.original_filename
136
- end
137
-
138
- it "returns a file name not enclosed in double quotes" do
139
- meta["content-disposition"] = "ATTACHMENT; FILENAME=#{file_name};"
140
-
141
- @subject = Paperclip.io_adapters.for(@uri)
142
-
143
- assert_equal file_name, @subject.original_filename
144
- end
145
-
146
- it "does not crash when an empty filename is given" do
147
- meta["content-disposition"] = "ATTACHMENT; FILENAME=\"\";"
148
-
149
- @subject = Paperclip.io_adapters.for(@uri)
150
-
151
- assert_equal "", @subject.original_filename
152
- end
153
-
154
- it "returns a file name ignoring RFC 5987 encoding" do
155
- meta["content-disposition"] =
156
- "attachment; filename=#{file_name}; filename* = utf-8''%e2%82%ac%20rates"
157
-
158
- @subject = Paperclip.io_adapters.for(@uri)
159
-
160
- assert_equal file_name, @subject.original_filename
161
- end
162
-
163
- context "when file name has consecutive periods" do
164
- let(:file_name) { "test_document..pdf" }
165
-
166
- it "returns a file name" do
167
- @uri = URI.parse(
168
- "https://github.com/thoughtbot/#{file_name}?file=test"
169
- )
170
- @subject = Paperclip.io_adapters.for(@uri)
171
- assert_equal file_name, @subject.original_filename
172
- end
173
- end
174
- end
175
-
176
- context "a url with restricted characters in the filename" do
177
- before do
178
- allow_any_instance_of(Paperclip::UriAdapter).
179
- to receive(:download_content).and_return(@open_return)
180
-
181
- @uri = URI.parse("https://github.com/thoughtbot/paper:clip.jpg")
182
- @subject = Paperclip.io_adapters.for(@uri)
183
- end
184
-
185
- it "does not generate filenames that include restricted characters" do
186
- assert_equal "paper_clip.jpg", @subject.original_filename
187
- end
188
-
189
- it "does not generate paths that include restricted characters" do
190
- expect(@subject.path).to_not match(/:/)
191
- end
192
- end
193
-
194
- describe "#download_content" do
195
- before do
196
- allowed_mock =
197
- if RUBY_VERSION < '2.5'
198
- allow_any_instance_of(Paperclip::UriAdapter)
199
- else
200
- allow(URI)
201
- end
202
-
203
- allowed_mock.to receive(:open).and_return(@open_return)
204
-
205
- @uri = URI.parse("https://github.com/thoughtbot/paper:clip.jpg")
206
- @subject = Paperclip.io_adapters.for(@uri)
207
- @uri_opener = RUBY_VERSION < '2.5' ? @subject : URI
208
- end
209
-
210
- after do
211
- @subject.send(:download_content)
212
- end
213
-
214
- context "with default read_timeout" do
215
- it "calls open without options" do
216
- expect(@uri_opener).to receive(:open).with(@uri, {}).at_least(1).times
217
- end
218
- end
219
-
220
- context "with custom read_timeout" do
221
- before do
222
- Paperclip.options[:read_timeout] = 120
223
- end
224
-
225
- it "calls open with read_timeout option" do
226
- expect(@uri_opener)
227
- .to receive(:open).with(@uri, { read_timeout: 120 }).at_least(1).times
228
- end
229
- end
230
- end
231
- end
@@ -1,266 +0,0 @@
1
- require "spec_helper"
2
-
3
- # This spec tests compatibility with Mastodon's LazyThumbnail pattern.
4
- # LazyThumbnail is a subclass of Paperclip::Thumbnail that conditionally
5
- # skips processing when the image doesn't need transformation.
6
- # See: https://github.com/mastodon/mastodon/blob/main/lib/paperclip/lazy_thumbnail.rb
7
-
8
- module Paperclip
9
- class LazyThumbnail < Paperclip::Thumbnail
10
- def make
11
- return File.open(@file.path) unless needs_convert?
12
-
13
- if options[:geometry]
14
- min_side = [@current_geometry.width, @current_geometry.height].min.to_i
15
- options[:geometry] = "#{min_side}x#{min_side}#" if @target_geometry.square? && min_side < @target_geometry.width
16
- elsif options[:pixels]
17
- width = Math.sqrt(options[:pixels] * (@current_geometry.width.to_f / @current_geometry.height)).round.to_i
18
- height = Math.sqrt(options[:pixels] * (@current_geometry.height.to_f / @current_geometry.width)).round.to_i
19
- options[:geometry] = "#{width}x#{height}>"
20
- end
21
-
22
- Paperclip::Thumbnail.make(file, options, attachment)
23
- end
24
-
25
- private
26
-
27
- def needs_convert?
28
- needs_different_geometry? || needs_different_format? || needs_metadata_stripping?
29
- end
30
-
31
- def needs_different_geometry?
32
- (options[:geometry] && @current_geometry.width != @target_geometry.width && @current_geometry.height != @target_geometry.height) ||
33
- (options[:pixels] && @current_geometry.width * @current_geometry.height > options[:pixels])
34
- end
35
-
36
- def needs_different_format?
37
- @format.present? && @current_format != @format
38
- end
39
-
40
- def needs_metadata_stripping?
41
- @attachment.respond_to?(:instance) && @attachment.instance.respond_to?(:local?) && @attachment.instance.local?
42
- end
43
- end
44
- end
45
-
46
- describe Paperclip::LazyThumbnail do
47
- let(:file) { File.new(fixture_file("5k.png"), "rb") }
48
- let(:rotated_file) { File.new(fixture_file("rotated.jpg"), "rb") }
49
- let(:attachment) { double("Attachment", options: {}, instance: double(local?: false)) }
50
-
51
- after do
52
- file.close
53
- rotated_file.close rescue nil
54
- end
55
-
56
- describe "basic compatibility" do
57
- it "inherits from Paperclip::Thumbnail" do
58
- expect(Paperclip::LazyThumbnail.superclass).to eq(Paperclip::Thumbnail)
59
- end
60
-
61
- it "can access current_geometry" do
62
- processor = described_class.new(file, { geometry: "100x100" }, attachment)
63
- expect(processor.current_geometry).to be_a(Paperclip::Geometry)
64
- expect(processor.current_geometry.width).to be > 0
65
- expect(processor.current_geometry.height).to be > 0
66
- end
67
-
68
- it "can access target_geometry" do
69
- processor = described_class.new(file, { geometry: "100x100#" }, attachment)
70
- expect(processor.target_geometry).to be_a(Paperclip::Geometry)
71
- expect(processor.target_geometry.width).to eq(100)
72
- expect(processor.target_geometry.height).to eq(100)
73
- end
74
-
75
- it "target_geometry responds to square?" do
76
- processor = described_class.new(file, { geometry: "100x100#" }, attachment)
77
- expect(processor.target_geometry).to respond_to(:square?)
78
- expect(processor.target_geometry.square?).to be true
79
- end
80
-
81
- it "can access format and current_format" do
82
- processor = described_class.new(file, { geometry: "100x100", format: :jpg }, attachment)
83
- expect(processor.format).to eq(:jpg)
84
- end
85
- end
86
-
87
- describe "with ImageMagick backend" do
88
- let(:attachment) { double("Attachment", options: { backend: :image_magick }, instance: double(local?: false)) }
89
-
90
- it "processes images when geometry change is needed" do
91
- processor = described_class.new(file, { geometry: "50x50#" }, attachment)
92
- result = processor.make
93
-
94
- expect(File.exist?(result.path)).to be true
95
- dimensions = `identify -format "%wx%h" "#{result.path}"`.strip
96
- expect(dimensions).to eq("50x50")
97
- end
98
-
99
- it "processes images when format change is needed" do
100
- processor = described_class.new(file, { geometry: "100x100", format: :jpg }, attachment)
101
- result = processor.make
102
-
103
- expect(File.exist?(result.path)).to be true
104
- expect(result.path).to end_with(".jpg")
105
- end
106
-
107
- it "skips processing when no changes needed" do
108
- # Create a processor where geometry matches source
109
- processor = described_class.new(file, { geometry: "434x66" }, attachment)
110
-
111
- # Since the source is 434x66 (5k.png dimensions), and target is same,
112
- # needs_different_geometry? returns false
113
- result = processor.make
114
-
115
- # Result should be the original file (File.open(@file.path))
116
- expect(File.exist?(result.path)).to be true
117
- end
118
-
119
- it "handles square geometry optimization" do
120
- # Source is 434x66, min_side is 66
121
- # Requesting 100x100# square, but min_side (66) < target width (100)
122
- # So geometry should be adjusted to "66x66#"
123
- processor = described_class.new(file, { geometry: "100x100#" }, attachment)
124
- result = processor.make
125
-
126
- expect(File.exist?(result.path)).to be true
127
- dimensions = `identify -format "%wx%h" "#{result.path}"`.strip
128
- expect(dimensions).to eq("66x66")
129
- end
130
- end
131
-
132
- describe "with libvips backend" do
133
- let(:attachment) { double("Attachment", options: { backend: :vips }, instance: double(local?: false)) }
134
-
135
- before do
136
- begin
137
- require "vips"
138
- rescue LoadError
139
- skip "libvips not installed"
140
- end
141
- end
142
-
143
- it "processes images when geometry change is needed" do
144
- processor = described_class.new(file, { geometry: "50x50#" }, attachment)
145
- result = processor.make
146
-
147
- expect(File.exist?(result.path)).to be true
148
- dimensions = `identify -format "%wx%h" "#{result.path}"`.strip
149
- expect(dimensions).to eq("50x50")
150
- end
151
-
152
- it "processes images when format change is needed" do
153
- processor = described_class.new(file, { geometry: "100x100", format: :jpg }, attachment)
154
- result = processor.make
155
-
156
- expect(File.exist?(result.path)).to be true
157
- expect(result.path).to end_with(".jpg")
158
- end
159
-
160
- it "skips processing when no changes needed" do
161
- processor = described_class.new(file, { geometry: "434x66" }, attachment)
162
- result = processor.make
163
- expect(File.exist?(result.path)).to be true
164
- end
165
-
166
- it "handles square geometry optimization" do
167
- processor = described_class.new(file, { geometry: "100x100#" }, attachment)
168
- result = processor.make
169
-
170
- expect(File.exist?(result.path)).to be true
171
- dimensions = `identify -format "%wx%h" "#{result.path}"`.strip
172
- expect(dimensions).to eq("66x66")
173
- end
174
- end
175
-
176
- describe "pixels-based resizing (Mastodon-specific)" do
177
- let(:attachment) { double("Attachment", options: {}, instance: double(local?: false)) }
178
-
179
- context "with ImageMagick backend" do
180
- let(:attachment) { double("Attachment", options: { backend: :image_magick }, instance: double(local?: false)) }
181
-
182
- it "resizes based on maximum pixel count" do
183
- # Source is 434x66 = 28,644 pixels
184
- # Request max 10,000 pixels
185
- processor = described_class.new(file, { pixels: 10_000 }, attachment)
186
- result = processor.make
187
-
188
- expect(File.exist?(result.path)).to be true
189
- dimensions = `identify -format "%wx%h" "#{result.path}"`.strip
190
- width, height = dimensions.split("x").map(&:to_i)
191
- expect(width * height).to be <= 10_000
192
- end
193
-
194
- it "skips processing when image is already small enough" do
195
- # Source is 434x66 = 28,644 pixels
196
- # Request max 50,000 pixels - no resize needed
197
- processor = described_class.new(file, { pixels: 50_000 }, attachment)
198
- result = processor.make
199
-
200
- expect(File.exist?(result.path)).to be true
201
- end
202
- end
203
-
204
- context "with libvips backend" do
205
- let(:attachment) { double("Attachment", options: { backend: :vips }, instance: double(local?: false)) }
206
-
207
- before do
208
- begin
209
- require "vips"
210
- rescue LoadError
211
- skip "libvips not installed"
212
- end
213
- end
214
-
215
- it "resizes based on maximum pixel count" do
216
- processor = described_class.new(file, { pixels: 10_000 }, attachment)
217
- result = processor.make
218
-
219
- expect(File.exist?(result.path)).to be true
220
- dimensions = `identify -format "%wx%h" "#{result.path}"`.strip
221
- width, height = dimensions.split("x").map(&:to_i)
222
- expect(width * height).to be <= 10_000
223
- end
224
- end
225
- end
226
-
227
- describe "metadata stripping trigger" do
228
- it "processes when attachment instance is local" do
229
- local_instance = double(local?: true)
230
- local_attachment = double("Attachment", options: {}, instance: local_instance)
231
-
232
- processor = described_class.new(file, { geometry: "434x66" }, local_attachment)
233
-
234
- # Even with matching geometry, should process because local? is true
235
- # This is verified by the fact that make doesn't just return the original file
236
- result = processor.make
237
- expect(File.exist?(result.path)).to be true
238
- end
239
- end
240
-
241
- describe "Thumbnail.make class method" do
242
- it "is available and works correctly" do
243
- expect(Paperclip::Thumbnail).to respond_to(:make)
244
-
245
- result = Paperclip::Thumbnail.make(file, { geometry: "50x50#" }, attachment)
246
- expect(File.exist?(result.path)).to be true
247
-
248
- dimensions = `identify -format "%wx%h" "#{result.path}"`.strip
249
- expect(dimensions).to eq("50x50")
250
- end
251
-
252
- it "respects backend option" do
253
- begin
254
- require "vips"
255
- rescue LoadError
256
- skip "libvips not installed"
257
- end
258
-
259
- result = Paperclip::Thumbnail.make(file, { geometry: "50x50#", backend: :vips }, attachment)
260
- expect(File.exist?(result.path)).to be true
261
-
262
- dimensions = `identify -format "%wx%h" "#{result.path}"`.strip
263
- expect(dimensions).to eq("50x50")
264
- end
265
- end
266
- end
@@ -1,19 +0,0 @@
1
- require "spec_helper"
2
- require "paperclip/matchers"
3
-
4
- describe Paperclip::Shoulda::Matchers::HaveAttachedFileMatcher do
5
- extend Paperclip::Shoulda::Matchers
6
-
7
- it "rejects the dummy class if it has no attachment" do
8
- reset_table "dummies"
9
- reset_class "Dummy"
10
- matcher = self.class.have_attached_file(:avatar)
11
- expect(matcher).to_not accept(Dummy)
12
- end
13
-
14
- it "accepts the dummy class if it has an attachment" do
15
- rebuild_model
16
- matcher = self.class.have_attached_file(:avatar)
17
- expect(matcher).to accept(Dummy)
18
- end
19
- end
@@ -1,108 +0,0 @@
1
- require "spec_helper"
2
- require "paperclip/matchers"
3
-
4
- describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
5
- extend Paperclip::Shoulda::Matchers
6
-
7
- before do
8
- reset_table("dummies") do |d|
9
- d.string :title
10
- d.string :avatar_file_name
11
- d.string :avatar_content_type
12
- end
13
- reset_class "Dummy"
14
- Dummy.do_not_validate_attachment_file_type :avatar
15
- Dummy.has_attached_file :avatar
16
- end
17
-
18
- it "rejects a class with no validation" do
19
- expect(matcher).to_not accept(Dummy)
20
- expect { matcher.failure_message }.to_not raise_error
21
- end
22
-
23
- it "rejects a class when the validation fails" do
24
- Dummy.validates_attachment_content_type :avatar, content_type: %r{audio/.*}
25
- expect(matcher).to_not accept(Dummy)
26
- expect { matcher.failure_message }.to_not raise_error
27
- end
28
-
29
- it "accepts a class with a matching validation" do
30
- Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
31
- expect(matcher).to accept(Dummy)
32
- expect { matcher.failure_message }.to_not raise_error
33
- end
34
-
35
- it "accepts a class with other validations but matching types" do
36
- Dummy.validates_presence_of :title
37
- Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
38
- expect(matcher).to accept(Dummy)
39
- expect { matcher.failure_message }.to_not raise_error
40
- end
41
-
42
- it "accepts a class that matches and a matcher that only specifies 'allowing'" do
43
- Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
44
- matcher = plain_matcher.allowing(%w(image/png image/jpeg))
45
-
46
- expect(matcher).to accept(Dummy)
47
- expect { matcher.failure_message }.to_not raise_error
48
- end
49
-
50
- it "rejects a class that does not match and a matcher that only specifies 'allowing'" do
51
- Dummy.validates_attachment_content_type :avatar, content_type: %r{audio/.*}
52
- matcher = plain_matcher.allowing(%w(image/png image/jpeg))
53
-
54
- expect(matcher).to_not accept(Dummy)
55
- expect { matcher.failure_message }.to_not raise_error
56
- end
57
-
58
- it "accepts a class that matches and a matcher that only specifies 'rejecting'" do
59
- Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
60
- matcher = plain_matcher.rejecting(%w(audio/mp3 application/octet-stream))
61
-
62
- expect(matcher).to accept(Dummy)
63
- expect { matcher.failure_message }.to_not raise_error
64
- end
65
-
66
- it "rejects a class that does not match and a matcher that only specifies 'rejecting'" do
67
- Dummy.validates_attachment_content_type :avatar, content_type: %r{audio/.*}
68
- matcher = plain_matcher.rejecting(%w(audio/mp3 application/octet-stream))
69
-
70
- expect(matcher).to_not accept(Dummy)
71
- expect { matcher.failure_message }.to_not raise_error
72
- end
73
-
74
- context "using an :if to control the validation" do
75
- before do
76
- Dummy.class_eval do
77
- validates_attachment_content_type :avatar, content_type: %r{image/*}, if: :go
78
- attr_accessor :go
79
- end
80
- end
81
-
82
- it "runs the validation if the control is true" do
83
- dummy = Dummy.new
84
- dummy.go = true
85
- expect(matcher).to accept(dummy)
86
- expect { matcher.failure_message }.to_not raise_error
87
- end
88
-
89
- it "does not run the validation if the control is false" do
90
- dummy = Dummy.new
91
- dummy.go = false
92
- expect(matcher).to_not accept(dummy)
93
- expect { matcher.failure_message }.to_not raise_error
94
- end
95
- end
96
-
97
- private
98
-
99
- def plain_matcher
100
- self.class.validate_attachment_content_type(:avatar)
101
- end
102
-
103
- def matcher
104
- plain_matcher.
105
- allowing(%w(image/png image/jpeg)).
106
- rejecting(%w(audio/mp3 application/octet-stream))
107
- end
108
- end
@@ -1,69 +0,0 @@
1
- require "spec_helper"
2
- require "paperclip/matchers"
3
-
4
- describe Paperclip::Shoulda::Matchers::ValidateAttachmentPresenceMatcher do
5
- extend Paperclip::Shoulda::Matchers
6
-
7
- before do
8
- reset_table("dummies") do |d|
9
- d.string :avatar_file_name
10
- end
11
- reset_class "Dummy"
12
- Dummy.has_attached_file :avatar
13
- Dummy.do_not_validate_attachment_file_type :avatar
14
- end
15
-
16
- it "rejects a class with no validation" do
17
- expect(matcher).to_not accept(Dummy)
18
- end
19
-
20
- it "accepts a class with a matching validation" do
21
- Dummy.validates_attachment_presence :avatar
22
- expect(matcher).to accept(Dummy)
23
- end
24
-
25
- it "accepts an instance with other attachment validations" do
26
- reset_table("dummies") do |d|
27
- d.string :avatar_file_name
28
- d.string :avatar_content_type
29
- end
30
- Dummy.class_eval do
31
- validates_attachment_presence :avatar
32
- validates_attachment_content_type :avatar, content_type: "image/gif"
33
- end
34
- dummy = Dummy.new
35
-
36
- dummy.avatar = File.new fixture_file("5k.png")
37
-
38
- expect(matcher).to accept(dummy)
39
- end
40
-
41
- context "using an :if to control the validation" do
42
- before do
43
- Dummy.class_eval do
44
- validates_attachment_presence :avatar, if: :go
45
- attr_accessor :go
46
- end
47
- end
48
-
49
- it "runs the validation if the control is true" do
50
- dummy = Dummy.new
51
- dummy.avatar = nil
52
- dummy.go = true
53
- expect(matcher).to accept(dummy)
54
- end
55
-
56
- it "does not run the validation if the control is false" do
57
- dummy = Dummy.new
58
- dummy.avatar = nil
59
- dummy.go = false
60
- expect(matcher).to_not accept(dummy)
61
- end
62
- end
63
-
64
- private
65
-
66
- def matcher
67
- self.class.validate_attachment_presence(:avatar)
68
- end
69
- end