paperclip 4.3.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of paperclip might be problematic. Click here for more details.

Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +14 -13
  3. data/Appraisals +22 -9
  4. data/CONTRIBUTING.md +16 -5
  5. data/Gemfile +2 -8
  6. data/LICENSE +1 -1
  7. data/NEWS +49 -2
  8. data/README.md +126 -102
  9. data/UPGRADING +12 -9
  10. data/features/basic_integration.feature +1 -0
  11. data/features/migration.feature +0 -24
  12. data/features/step_definitions/attachment_steps.rb +20 -20
  13. data/features/step_definitions/html_steps.rb +2 -2
  14. data/features/step_definitions/rails_steps.rb +11 -17
  15. data/features/step_definitions/s3_steps.rb +2 -2
  16. data/features/step_definitions/web_steps.rb +1 -103
  17. data/features/support/file_helpers.rb +2 -2
  18. data/gemfiles/4.2.awsv2.0.gemfile +17 -0
  19. data/gemfiles/4.2.awsv2.1.gemfile +17 -0
  20. data/gemfiles/{4.2.gemfile → 4.2.awsv2.gemfile} +1 -1
  21. data/gemfiles/5.0.awsv2.0.gemfile +17 -0
  22. data/gemfiles/5.0.awsv2.1.gemfile +17 -0
  23. data/gemfiles/{4.1.gemfile → 5.0.awsv2.gemfile} +2 -2
  24. data/lib/paperclip/attachment.rb +18 -17
  25. data/lib/paperclip/attachment_registry.rb +2 -1
  26. data/lib/paperclip/callbacks.rb +8 -6
  27. data/lib/paperclip/content_type_detector.rb +3 -2
  28. data/lib/paperclip/errors.rb +3 -1
  29. data/lib/paperclip/geometry_parser_factory.rb +1 -1
  30. data/lib/paperclip/glue.rb +1 -1
  31. data/lib/paperclip/has_attached_file.rb +7 -1
  32. data/lib/paperclip/helpers.rb +14 -10
  33. data/lib/paperclip/interpolations/plural_cache.rb +6 -5
  34. data/lib/paperclip/interpolations.rb +18 -13
  35. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +1 -1
  36. data/lib/paperclip/io_adapters/uri_adapter.rb +3 -1
  37. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +4 -4
  38. data/lib/paperclip/media_type_spoof_detector.rb +1 -1
  39. data/lib/paperclip/rails_environment.rb +1 -1
  40. data/lib/paperclip/schema.rb +3 -9
  41. data/lib/paperclip/storage/fog.rb +17 -8
  42. data/lib/paperclip/storage/s3.rb +51 -49
  43. data/lib/paperclip/validators/attachment_size_validator.rb +1 -7
  44. data/lib/paperclip/version.rb +3 -1
  45. data/lib/paperclip.rb +2 -1
  46. data/lib/tasks/paperclip.rake +1 -1
  47. data/paperclip.gemspec +15 -11
  48. data/spec/paperclip/attachment_processing_spec.rb +2 -4
  49. data/spec/paperclip/attachment_registry_spec.rb +28 -0
  50. data/spec/paperclip/attachment_spec.rb +36 -14
  51. data/spec/paperclip/geometry_spec.rb +1 -1
  52. data/spec/paperclip/glue_spec.rb +44 -0
  53. data/spec/paperclip/has_attached_file_spec.rb +24 -8
  54. data/spec/paperclip/integration_spec.rb +4 -3
  55. data/spec/paperclip/interpolations_spec.rb +14 -4
  56. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +12 -0
  57. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +27 -0
  58. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +10 -0
  59. data/spec/paperclip/media_type_spoof_detector_spec.rb +12 -3
  60. data/spec/paperclip/paperclip_spec.rb +3 -28
  61. data/spec/paperclip/plural_cache_spec.rb +17 -16
  62. data/spec/paperclip/storage/fog_spec.rb +31 -1
  63. data/spec/paperclip/storage/s3_live_spec.rb +8 -4
  64. data/spec/paperclip/storage/s3_spec.rb +213 -156
  65. data/spec/paperclip/validators/attachment_size_validator_spec.rb +26 -20
  66. data/spec/paperclip/validators_spec.rb +3 -3
  67. data/spec/spec_helper.rb +6 -1
  68. data/spec/support/assertions.rb +7 -0
  69. data/spec/support/model_reconstruction.rb +9 -1
  70. data/spec/support/reporting.rb +11 -0
  71. metadata +74 -47
  72. data/cucumber/paperclip_steps.rb +0 -6
  73. data/gemfiles/3.2.gemfile +0 -20
  74. data/lib/paperclip/locales/de.yml +0 -18
  75. data/lib/paperclip/locales/es.yml +0 -18
  76. data/lib/paperclip/locales/ja.yml +0 -18
  77. data/lib/paperclip/locales/pt-BR.yml +0 -18
  78. data/lib/paperclip/locales/zh-CN.yml +0 -18
  79. data/lib/paperclip/locales/zh-HK.yml +0 -18
  80. data/lib/paperclip/locales/zh-TW.yml +0 -18
  81. data/spec/support/rails_helpers.rb +0 -7
@@ -1,3 +1,5 @@
1
1
  module Paperclip
2
- VERSION = "4.3.0" unless defined? Paperclip::VERSION
2
+ unless defined?(Paperclip::VERSION)
3
+ VERSION = "5.0.0".freeze
4
+ end
3
5
  end
data/lib/paperclip.rb CHANGED
@@ -97,7 +97,8 @@ module Paperclip
97
97
  :log_command => true,
98
98
  :swallow_stderr => true,
99
99
  :content_type_mappings => {},
100
- :use_exif_orientation => true
100
+ :use_exif_orientation => true,
101
+ :read_timeout => nil
101
102
  }
102
103
  end
103
104
 
@@ -18,7 +18,7 @@ module Paperclip
18
18
  raise "Class #{klass.name} has no attachments specified"
19
19
  end
20
20
 
21
- if !name.blank? && attachment_names.map(&:to_s).include?(name.to_s)
21
+ if name.present? && attachment_names.map(&:to_s).include?(name.to_s)
22
22
  [ name ]
23
23
  else
24
24
  attachment_names
data/paperclip.gemspec CHANGED
@@ -17,34 +17,38 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ["lib"]
19
19
 
20
+ if File.exist?('UPGRADING')
21
+ s.post_install_message = File.read("UPGRADING")
22
+ end
23
+
20
24
  s.requirements << "ImageMagick"
21
- s.required_ruby_version = ">= 1.9.2"
25
+ s.required_ruby_version = ">= 2.1.0"
22
26
 
23
- s.add_dependency('activemodel', '>= 3.2.0')
24
- s.add_dependency('activesupport', '>= 3.2.0')
27
+ s.add_dependency('activemodel', '>= 4.2.0')
28
+ s.add_dependency('activesupport', '>= 4.2.0')
25
29
  s.add_dependency('cocaine', '~> 0.5.5')
26
30
  s.add_dependency('mime-types')
27
- s.add_dependency('mimemagic', '0.3.0')
31
+ s.add_dependency('mimemagic', '~> 0.3.0')
28
32
 
29
- s.add_development_dependency('activerecord', '>= 3.2.0')
33
+ s.add_development_dependency('activerecord', '>= 4.2.0')
30
34
  s.add_development_dependency('shoulda')
31
- s.add_development_dependency('rspec')
35
+ s.add_development_dependency('rspec', '~> 3.0')
32
36
  s.add_development_dependency('appraisal')
33
37
  s.add_development_dependency('mocha')
34
- s.add_development_dependency('aws-sdk', '>= 1.5.7', "<= 2.0")
38
+ s.add_development_dependency('aws-sdk', '>= 2.0.34', '< 3.0')
35
39
  s.add_development_dependency('bourne')
36
40
  s.add_development_dependency('cucumber', '~> 1.3.18')
37
- s.add_development_dependency('aruba')
41
+ s.add_development_dependency('aruba', '~> 0.9.0')
38
42
  s.add_development_dependency('nokogiri')
39
- # Ruby version < 1.9.3 can't install capybara > 2.0.3.
40
43
  s.add_development_dependency('capybara')
41
44
  s.add_development_dependency('bundler')
42
- s.add_development_dependency('fog', '~> 1.0')
45
+ s.add_development_dependency('fog-aws')
46
+ s.add_development_dependency('fog-local')
43
47
  s.add_development_dependency('launchy')
44
48
  s.add_development_dependency('rake')
45
49
  s.add_development_dependency('fakeweb')
46
50
  s.add_development_dependency('railties')
47
- s.add_development_dependency('actionmailer', '>= 3.2.0')
51
+ s.add_development_dependency('actionmailer', '>= 4.2.0')
48
52
  s.add_development_dependency('generator_spec')
49
53
  s.add_development_dependency('timecop')
50
54
  end
@@ -2,11 +2,9 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe 'Attachment Processing' do
5
- context 'using validates_attachment_content_type' do
6
- before do
7
- rebuild_class
8
- end
5
+ before { rebuild_class }
9
6
 
7
+ context 'using validates_attachment_content_type' do
10
8
  it 'processes attachments given a valid assignment' do
11
9
  file = File.new(fixture_file("5k.png"))
12
10
  Dummy.validates_attachment_content_type :avatar, content_type: "image/png"
@@ -111,6 +111,34 @@ describe 'Attachment Registry' do
111
111
 
112
112
  assert_equal expected_definitions, definitions
113
113
  end
114
+
115
+ it 'allows subclasses to override attachment defitions' do
116
+ foo_definitions = { avatar: { yo: "greeting" } }
117
+ bar_definitions = { avatar: { yo: "hello" } }
118
+
119
+ expected_definitions = {
120
+ avatar: {
121
+ yo: "hello"
122
+ }
123
+ }
124
+
125
+ foo = Class.new
126
+ bar = Class.new(foo)
127
+ Paperclip::AttachmentRegistry.register(
128
+ foo,
129
+ :avatar,
130
+ foo_definitions[:avatar]
131
+ )
132
+ Paperclip::AttachmentRegistry.register(
133
+ bar,
134
+ :avatar,
135
+ bar_definitions[:avatar]
136
+ )
137
+
138
+ definitions = Paperclip::AttachmentRegistry.definitions_for(bar)
139
+
140
+ assert_equal expected_definitions, definitions
141
+ end
114
142
  end
115
143
 
116
144
  context '.clear' do
@@ -222,9 +222,6 @@ describe Paperclip::Attachment do
222
222
  dummy.avatar_file_name = "fake.jpg"
223
223
  dummy.stubs(:new_record?).returns(false)
224
224
  expected_string = '{"avatar":"/system/dummies/avatars/000/001/234/original/fake.jpg"}'
225
- if ActiveRecord::Base.include_root_in_json # This is true by default in Rails 3, and false in 4
226
- expected_string = %({"dummy":#{expected_string}})
227
- end
228
225
  # active_model pre-3.2 checks only by calling any? on it, thus it doesn't work if it is empty
229
226
  assert_equal expected_string, dummy.to_json(only: [:dummy_key_for_old_active_model], methods: [:avatar])
230
227
  end
@@ -254,6 +251,7 @@ describe Paperclip::Attachment do
254
251
 
255
252
  context "without an Attachment" do
256
253
  before do
254
+ rebuild_model default_url: "default.url"
257
255
  @dummy = Dummy.new
258
256
  end
259
257
 
@@ -261,8 +259,8 @@ describe Paperclip::Attachment do
261
259
  assert !@dummy.avatar.exists?
262
260
  end
263
261
 
264
- it "#url returns nil" do
265
- assert_nil @dummy.avatar.url
262
+ it "#url returns the default_url" do
263
+ expect(@dummy.avatar.url).to eq "default.url"
266
264
  end
267
265
  end
268
266
 
@@ -699,9 +697,6 @@ describe Paperclip::Attachment do
699
697
 
700
698
  context "when assigned" do
701
699
  it "calls #make on all specified processors" do
702
- Paperclip::Thumbnail.stubs(:make).with(any_parameters).returns(@file)
703
- Paperclip::Test.stubs(:make).with(any_parameters).returns(@file)
704
-
705
700
  @dummy.avatar = @file
706
701
 
707
702
  expect(Paperclip::Thumbnail).to have_received(:make)
@@ -716,7 +711,6 @@ describe Paperclip::Attachment do
716
711
  convert_options: "",
717
712
  source_file_options: ""
718
713
  })
719
- Paperclip::Thumbnail.stubs(:make).returns(@file)
720
714
 
721
715
  @dummy.avatar = @file
722
716
 
@@ -724,12 +718,36 @@ describe Paperclip::Attachment do
724
718
  end
725
719
 
726
720
  it "calls #make with attachment passed as third argument" do
727
- Paperclip::Test.expects(:make).returns(@file)
728
-
729
721
  @dummy.avatar = @file
730
722
 
731
723
  expect(Paperclip::Test).to have_received(:make).with(anything, anything, @dummy.avatar)
732
724
  end
725
+
726
+ it "calls #make and unlinks intermediary files afterward" do
727
+ @dummy.avatar.expects(:unlink_files).with([@file, @file])
728
+
729
+ @dummy.avatar = @file
730
+ end
731
+ end
732
+ end
733
+
734
+ context "An attachment with a processor that returns original file" do
735
+ before do
736
+ class Paperclip::Test < Paperclip::Processor
737
+ def make; @file; end
738
+ end
739
+ rebuild_model processors: [:test], styles: { once: "100x100" }
740
+ @file = StringIO.new("...")
741
+ @file.stubs(:close)
742
+ @dummy = Dummy.new
743
+ end
744
+
745
+ context "when assigned" do
746
+ it "#calls #make and doesn't unlink the original file" do
747
+ @dummy.avatar.expects(:unlink_files).with([])
748
+
749
+ @dummy.avatar = @file
750
+ end
733
751
  end
734
752
  end
735
753
 
@@ -1103,7 +1121,7 @@ describe Paperclip::Attachment do
1103
1121
  context "with a file assigned but not saved yet" do
1104
1122
  it "clears out any attached files" do
1105
1123
  @attachment.assign(@file)
1106
- assert !@attachment.queued_for_write.blank?
1124
+ assert @attachment.queued_for_write.present?
1107
1125
  @attachment.clear
1108
1126
  assert @attachment.queued_for_write.blank?
1109
1127
  end
@@ -1353,6 +1371,12 @@ describe Paperclip::Attachment do
1353
1371
  end
1354
1372
 
1355
1373
  it "does not calculate fingerprint" do
1374
+ Digest::MD5.stubs(:file)
1375
+ @dummy.avatar = @file
1376
+ expect(Digest::MD5).to have_received(:file).never
1377
+ end
1378
+
1379
+ it "does not assign fingerprint" do
1356
1380
  @dummy.avatar = @file
1357
1381
  assert_nil @dummy.avatar.fingerprint
1358
1382
  end
@@ -1490,6 +1514,4 @@ describe Paperclip::Attachment do
1490
1514
  assert_file_exists(@path)
1491
1515
  end
1492
1516
  end
1493
-
1494
1517
  end
1495
-
@@ -82,7 +82,7 @@ describe Paperclip::Geometry do
82
82
  assert_equal 456, @upper.height
83
83
  end
84
84
 
85
- ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod|
85
+ ['>', '<', '#', '@', '@>', '>@', '%', '^', '!', nil].each do |mod|
86
86
  it "ensures the modifier #{description} is preserved" do
87
87
  assert @geo = Paperclip::Geometry.parse("123x456#{mod}")
88
88
  assert_equal mod, @geo.modifier
@@ -0,0 +1,44 @@
1
+ # require "spec_helper"
2
+
3
+ describe Paperclip::Glue do
4
+ describe "when ActiveRecord does not exist" do
5
+ before do
6
+ ActiveRecordSaved = ActiveRecord
7
+ Object.send :remove_const, "ActiveRecord"
8
+ end
9
+
10
+ after do
11
+ ActiveRecord = ActiveRecordSaved
12
+ Object.send :remove_const, "ActiveRecordSaved"
13
+ end
14
+
15
+ it "does not fail" do
16
+ NonActiveRecordModel = Class.new
17
+ NonActiveRecordModel.send :include, Paperclip::Glue
18
+ Object.send :remove_const, "NonActiveRecordModel"
19
+ end
20
+ end
21
+
22
+ describe "when ActiveRecord does exist" do
23
+ before do
24
+ if Object.const_defined?("ActiveRecord")
25
+ @defined_active_record = false
26
+ else
27
+ ActiveRecord = :defined
28
+ @defined_active_record = true
29
+ end
30
+ end
31
+
32
+ after do
33
+ if @defined_active_record
34
+ Object.send :remove_const, "ActiveRecord"
35
+ end
36
+ end
37
+
38
+ it "does not fail" do
39
+ NonActiveRecordModel = Class.new
40
+ NonActiveRecordModel.send :include, Paperclip::Glue
41
+ Object.send :remove_const, "NonActiveRecordModel"
42
+ end
43
+ end
44
+ end
@@ -38,6 +38,15 @@ describe Paperclip::HasAttachedFile do
38
38
  assert_adding_attachment('avatar').defines_callback('after_commit')
39
39
  end
40
40
 
41
+ context 'when the class does not allow after_commit callbacks' do
42
+ it 'defines an after_destroy callback' do
43
+ assert_adding_attachment(
44
+ 'avatar',
45
+ unstub_methods: [:after_commit]
46
+ ).defines_callback('after_destroy')
47
+ end
48
+ end
49
+
41
50
  it 'defines the Paperclip-specific callbacks' do
42
51
  assert_adding_attachment('avatar').defines_callback('define_paperclip_callbacks')
43
52
  end
@@ -53,20 +62,26 @@ describe Paperclip::HasAttachedFile do
53
62
 
54
63
  private
55
64
 
56
- def assert_adding_attachment(attachment_name)
57
- AttachmentAdder.new(attachment_name)
65
+ def assert_adding_attachment(attachment_name, options={})
66
+ AttachmentAdder.new(attachment_name, options)
58
67
  end
59
68
 
60
69
  class AttachmentAdder
61
70
  include Mocha::API
62
71
  include RSpec::Matchers
63
72
 
64
- def initialize(attachment_name)
73
+ def initialize(attachment_name, options = {})
65
74
  @attachment_name = attachment_name
75
+ @stubbed_class = stub_class
76
+ if options.present?
77
+ options[:unstub_methods].each do |method|
78
+ @stubbed_class.unstub(method)
79
+ end
80
+ end
66
81
  end
67
82
 
68
83
  def defines_method(method_name)
69
- a_class = stub_class
84
+ a_class = @stubbed_class
70
85
 
71
86
  Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
72
87
 
@@ -74,7 +89,7 @@ describe Paperclip::HasAttachedFile do
74
89
  end
75
90
 
76
91
  def defines_class_method(method_name)
77
- a_class = stub_class
92
+ a_class = @stubbed_class
78
93
  a_class.class.stubs(:define_method)
79
94
 
80
95
  Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
@@ -83,7 +98,7 @@ describe Paperclip::HasAttachedFile do
83
98
  end
84
99
 
85
100
  def defines_validation
86
- a_class = stub_class
101
+ a_class = @stubbed_class
87
102
 
88
103
  Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
89
104
 
@@ -91,7 +106,7 @@ describe Paperclip::HasAttachedFile do
91
106
  end
92
107
 
93
108
  def registers_attachment
94
- a_class = stub_class
109
+ a_class = @stubbed_class
95
110
  Paperclip::AttachmentRegistry.stubs(:register)
96
111
 
97
112
  Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {size: 1})
@@ -100,7 +115,7 @@ describe Paperclip::HasAttachedFile do
100
115
  end
101
116
 
102
117
  def defines_callback(callback_name)
103
- a_class = stub_class
118
+ a_class = @stubbed_class
104
119
 
105
120
  Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
106
121
 
@@ -132,6 +147,7 @@ describe Paperclip::HasAttachedFile do
132
147
  after_save: nil,
133
148
  before_destroy: nil,
134
149
  after_commit: nil,
150
+ after_destroy: nil,
135
151
  define_paperclip_callbacks: nil,
136
152
  extend: nil,
137
153
  name: 'Billy',
@@ -7,9 +7,10 @@ describe 'Paperclip' do
7
7
  before do
8
8
  rebuild_model
9
9
  @file = File.new(fixture_file("5k.png"), 'rb')
10
- 300.times do |i|
11
- Dummy.create! avatar: @file
12
- end
10
+ # Deals with `Too many open files` error
11
+ Dummy.import 100.times.map { Dummy.new avatar: @file }
12
+ Dummy.import 100.times.map { Dummy.new avatar: @file }
13
+ Dummy.import 100.times.map { Dummy.new avatar: @file }
13
14
  end
14
15
 
15
16
  after { @file.close }
@@ -24,15 +24,16 @@ describe Paperclip::Interpolations do
24
24
  end
25
25
 
26
26
  it "returns the class of the instance" do
27
+ class Thing ; end
27
28
  attachment = mock
28
29
  attachment.expects(:instance).returns(attachment)
29
- attachment.expects(:class).returns("Thing")
30
+ attachment.expects(:class).returns(Thing)
30
31
  assert_equal "things", Paperclip::Interpolations.class(attachment, :style)
31
32
  end
32
33
 
33
34
  it "returns the basename of the file" do
34
35
  attachment = mock
35
- attachment.expects(:original_filename).returns("one.jpg").times(2)
36
+ attachment.expects(:original_filename).returns("one.jpg").times(1)
36
37
  assert_equal "one", Paperclip::Interpolations.basename(attachment, :style)
37
38
  end
38
39
 
@@ -187,14 +188,14 @@ describe Paperclip::Interpolations do
187
188
  it "returns the filename as basename.extension" do
188
189
  attachment = mock
189
190
  attachment.expects(:styles).returns({})
190
- attachment.expects(:original_filename).returns("one.jpg").times(3)
191
+ attachment.expects(:original_filename).returns("one.jpg").times(2)
191
192
  assert_equal "one.jpg", Paperclip::Interpolations.filename(attachment, :style)
192
193
  end
193
194
 
194
195
  it "returns the filename as basename.extension when format supplied" do
195
196
  attachment = mock
196
197
  attachment.expects(:styles).returns({style: {format: :png}})
197
- attachment.expects(:original_filename).returns("one.jpg").times(2)
198
+ attachment.expects(:original_filename).returns("one.jpg").times(1)
198
199
  assert_equal "one.png", Paperclip::Interpolations.filename(attachment, :style)
199
200
  end
200
201
 
@@ -249,4 +250,13 @@ describe Paperclip::Interpolations do
249
250
  value = Paperclip::Interpolations.interpolate(":notreal/:id/:attachment", :attachment, :style)
250
251
  assert_equal ":notreal/1234/attachments", value
251
252
  end
253
+
254
+ it "handles question marks" do
255
+ Paperclip.interpolates :foo? do
256
+ "bar"
257
+ end
258
+ Paperclip::Interpolations.expects(:fool).never
259
+ value = Paperclip::Interpolations.interpolate(":fo/:foo?")
260
+ assert_equal ":fo/bar", value
261
+ end
252
262
  end
@@ -98,4 +98,16 @@ describe Paperclip::HttpUrlProxyAdapter do
98
98
  end
99
99
  end
100
100
 
101
+ context "a url with special characters in the filename" do
102
+ it "returns a encoded filename" do
103
+ Paperclip::HttpUrlProxyAdapter.any_instance.stubs(:download_content).
104
+ returns(StringIO.new("x"))
105
+ url = "https://github.com/thoughtbot/paperclip-öäü字´½♥زÈ.png"
106
+ subject = Paperclip.io_adapters.for(url)
107
+ filename = "paperclip-%C3%B6%C3%A4%C3%BC%E5%AD%97%C2%B4%C2%BD%E2%99%A5"\
108
+ "%C3%98%C2%B2%C3%88.png"
109
+
110
+ assert_equal filename, subject.original_filename
111
+ end
112
+ end
101
113
  end
@@ -99,4 +99,31 @@ describe Paperclip::UriAdapter do
99
99
  end
100
100
  end
101
101
 
102
+ describe "#download_content" do
103
+ before do
104
+ Paperclip::UriAdapter.any_instance.stubs(:open).returns(StringIO.new("xxx"))
105
+ @uri = URI.parse("https://github.com/thoughtbot/paper:clip.jpg")
106
+ @subject = Paperclip.io_adapters.for(@uri)
107
+ end
108
+
109
+ after do
110
+ @subject.send(:download_content)
111
+ end
112
+
113
+ context "with default read_timeout" do
114
+ it "calls open without options" do
115
+ @subject.expects(:open).with(@uri, {}).at_least_once
116
+ end
117
+ end
118
+
119
+ context "with custom read_timeout" do
120
+ before do
121
+ Paperclip.options[:read_timeout] = 120
122
+ end
123
+
124
+ it "calls open with read_timeout option" do
125
+ @subject.expects(:open).with(@uri, read_timeout: 120).at_least_once
126
+ end
127
+ end
128
+ end
102
129
  end
@@ -17,22 +17,26 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
17
17
 
18
18
  it "rejects a class with no validation" do
19
19
  expect(matcher).to_not accept(Dummy)
20
+ expect { matcher.failure_message }.to_not raise_error
20
21
  end
21
22
 
22
23
  it 'rejects a class when the validation fails' do
23
24
  Dummy.validates_attachment_content_type :avatar, content_type: %r{audio/.*}
24
25
  expect(matcher).to_not accept(Dummy)
26
+ expect { matcher.failure_message }.to_not raise_error
25
27
  end
26
28
 
27
29
  it "accepts a class with a matching validation" do
28
30
  Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
29
31
  expect(matcher).to accept(Dummy)
32
+ expect { matcher.failure_message }.to_not raise_error
30
33
  end
31
34
 
32
35
  it "accepts a class with other validations but matching types" do
33
36
  Dummy.validates_presence_of :title
34
37
  Dummy.validates_attachment_content_type :avatar, content_type: %r{image/.*}
35
38
  expect(matcher).to accept(Dummy)
39
+ expect { matcher.failure_message }.to_not raise_error
36
40
  end
37
41
 
38
42
  it "accepts a class that matches and a matcher that only specifies 'allowing'" do
@@ -40,6 +44,7 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
40
44
  matcher = plain_matcher.allowing(%w(image/png image/jpeg))
41
45
 
42
46
  expect(matcher).to accept(Dummy)
47
+ expect { matcher.failure_message }.to_not raise_error
43
48
  end
44
49
 
45
50
  it "rejects a class that does not match and a matcher that only specifies 'allowing'" do
@@ -47,6 +52,7 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
47
52
  matcher = plain_matcher.allowing(%w(image/png image/jpeg))
48
53
 
49
54
  expect(matcher).to_not accept(Dummy)
55
+ expect { matcher.failure_message }.to_not raise_error
50
56
  end
51
57
 
52
58
  it "accepts a class that matches and a matcher that only specifies 'rejecting'" do
@@ -54,6 +60,7 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
54
60
  matcher = plain_matcher.rejecting(%w(audio/mp3 application/octet-stream))
55
61
 
56
62
  expect(matcher).to accept(Dummy)
63
+ expect { matcher.failure_message }.to_not raise_error
57
64
  end
58
65
 
59
66
  it "rejects a class that does not match and a matcher that only specifies 'rejecting'" do
@@ -61,6 +68,7 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
61
68
  matcher = plain_matcher.rejecting(%w(audio/mp3 application/octet-stream))
62
69
 
63
70
  expect(matcher).to_not accept(Dummy)
71
+ expect { matcher.failure_message }.to_not raise_error
64
72
  end
65
73
 
66
74
  context "using an :if to control the validation" do
@@ -75,12 +83,14 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentContentTypeMatcher do
75
83
  dummy = Dummy.new
76
84
  dummy.go = true
77
85
  expect(matcher).to accept(dummy)
86
+ expect { matcher.failure_message }.to_not raise_error
78
87
  end
79
88
 
80
89
  it "does not run the validation if the control is false" do
81
90
  dummy = Dummy.new
82
91
  dummy.go = false
83
92
  expect(matcher).to_not accept(dummy)
93
+ expect { matcher.failure_message }.to_not raise_error
84
94
  end
85
95
  end
86
96
 
@@ -44,9 +44,18 @@ describe Paperclip::MediaTypeSpoofDetector do
44
44
  end
45
45
  end
46
46
 
47
- it "rejects a file if named .html and is as HTML, but we're told JPG" do
48
- file = File.open(fixture_file("empty.html"))
49
- assert Paperclip::MediaTypeSpoofDetector.using(file, "empty.html", "image/jpg").spoofed?
47
+ context "file named .html and is as HTML, but we're told JPG" do
48
+ let(:file) { File.open(fixture_file("empty.html")) }
49
+ let(:spoofed?) { Paperclip::MediaTypeSpoofDetector.using(file, "empty.html", "image/jpg").spoofed? }
50
+
51
+ it "rejects the file" do
52
+ assert spoofed?
53
+ end
54
+
55
+ it "logs info about the detected spoof" do
56
+ Paperclip.expects(:log).with('Content Type Spoof: Filename empty.html (image/jpg from Headers, ["text/html"] from Extension), content type discovered from file command: text/html. See documentation to allow this combination.')
57
+ spoofed?
58
+ end
50
59
  end
51
60
 
52
61
  it "does not reject if content_type is empty but otherwise checks out" do
@@ -29,7 +29,9 @@ describe Paperclip do
29
29
  Paperclip.options[:command_path] = "/opt/my_app/bin"
30
30
  Paperclip.run("convert", "stuff")
31
31
  Paperclip.run("convert", "more_stuff")
32
- assert_equal 1, [Cocaine::CommandLine.path].flatten.size
32
+
33
+ cmd_path = Paperclip.options[:command_path]
34
+ assert_equal 1, Cocaine::CommandLine.path.scan(cmd_path).count
33
35
  end
34
36
  end
35
37
 
@@ -123,33 +125,6 @@ describe Paperclip do
123
125
  end
124
126
  end
125
127
 
126
- if using_protected_attributes?
127
- context "that is attr_protected" do
128
- before do
129
- Dummy.class_eval do
130
- attr_protected :avatar
131
- end
132
- @dummy = Dummy.new
133
- end
134
-
135
- it "does not assign the avatar on mass-set" do
136
- @dummy.attributes = { other: "I'm set!",
137
- avatar: @file }
138
-
139
- assert_equal "I'm set!", @dummy.other
140
- assert ! @dummy.avatar?
141
- end
142
-
143
- it "allows assigment on normal set" do
144
- @dummy.other = "I'm set!"
145
- @dummy.avatar = @file
146
-
147
- assert_equal "I'm set!", @dummy.other
148
- assert @dummy.avatar?
149
- end
150
- end
151
- end
152
-
153
128
  context "with a subclass" do
154
129
  before do
155
130
  class ::SubDummy < Dummy; end