paperclip-v2_7-patched-ruby-1_8_6 2.7.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +14 -0
  4. data/Appraisals +20 -0
  5. data/CONTRIBUTING.md +38 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE +26 -0
  8. data/NEWS +69 -0
  9. data/README.md +444 -0
  10. data/Rakefile +41 -0
  11. data/cucumber/paperclip_steps.rb +6 -0
  12. data/features/basic_integration.feature +48 -0
  13. data/features/rake_tasks.feature +68 -0
  14. data/features/step_definitions/attachment_steps.rb +65 -0
  15. data/features/step_definitions/html_steps.rb +15 -0
  16. data/features/step_definitions/rails_steps.rb +193 -0
  17. data/features/step_definitions/s3_steps.rb +14 -0
  18. data/features/step_definitions/web_steps.rb +209 -0
  19. data/features/support/env.rb +8 -0
  20. data/features/support/fakeweb.rb +3 -0
  21. data/features/support/fixtures/.boot_config.rb.swo +0 -0
  22. data/features/support/fixtures/boot_config.txt +15 -0
  23. data/features/support/fixtures/gemfile.txt +5 -0
  24. data/features/support/fixtures/preinitializer.txt +20 -0
  25. data/features/support/paths.rb +28 -0
  26. data/features/support/rails.rb +46 -0
  27. data/features/support/selectors.rb +19 -0
  28. data/gemfiles/rails2.gemfile +9 -0
  29. data/gemfiles/rails3.gemfile +9 -0
  30. data/gemfiles/rails3_1.gemfile +9 -0
  31. data/gemfiles/rails3_2.gemfile +9 -0
  32. data/generators/paperclip/USAGE +5 -0
  33. data/generators/paperclip/paperclip_generator.rb +27 -0
  34. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  35. data/init.rb +4 -0
  36. data/lib/generators/paperclip/USAGE +8 -0
  37. data/lib/generators/paperclip/paperclip_generator.rb +33 -0
  38. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  39. data/lib/paperclip.rb +493 -0
  40. data/lib/paperclip/attachment.rb +491 -0
  41. data/lib/paperclip/attachment_options.rb +10 -0
  42. data/lib/paperclip/callback_compatibility.rb +61 -0
  43. data/lib/paperclip/geometry.rb +120 -0
  44. data/lib/paperclip/interpolations.rb +174 -0
  45. data/lib/paperclip/iostream.rb +45 -0
  46. data/lib/paperclip/matchers.rb +64 -0
  47. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  48. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
  49. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  50. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  51. data/lib/paperclip/missing_attachment_styles.rb +87 -0
  52. data/lib/paperclip/processor.rb +58 -0
  53. data/lib/paperclip/railtie.rb +35 -0
  54. data/lib/paperclip/schema.rb +39 -0
  55. data/lib/paperclip/storage.rb +3 -0
  56. data/lib/paperclip/storage/filesystem.rb +81 -0
  57. data/lib/paperclip/storage/fog.rb +191 -0
  58. data/lib/paperclip/storage/s3.rb +351 -0
  59. data/lib/paperclip/style.rb +103 -0
  60. data/lib/paperclip/thumbnail.rb +105 -0
  61. data/lib/paperclip/upfile.rb +64 -0
  62. data/lib/paperclip/url_generator.rb +64 -0
  63. data/lib/paperclip/version.rb +3 -0
  64. data/lib/tasks/paperclip.rake +101 -0
  65. data/paperclip.gemspec +41 -0
  66. data/rails/init.rb +2 -0
  67. data/shoulda_macros/paperclip.rb +124 -0
  68. data/test/attachment_options_test.rb +40 -0
  69. data/test/attachment_test.rb +1211 -0
  70. data/test/database.yml +4 -0
  71. data/test/fixtures/12k.png +0 -0
  72. data/test/fixtures/50x50.png +0 -0
  73. data/test/fixtures/5k.png +0 -0
  74. data/test/fixtures/animated.gif +0 -0
  75. data/test/fixtures/bad.png +1 -0
  76. data/test/fixtures/fog.yml +8 -0
  77. data/test/fixtures/s3.yml +8 -0
  78. data/test/fixtures/spaced file.png +0 -0
  79. data/test/fixtures/text.txt +1 -0
  80. data/test/fixtures/twopage.pdf +0 -0
  81. data/test/fixtures/uppercase.PNG +0 -0
  82. data/test/geometry_test.rb +206 -0
  83. data/test/helper.rb +181 -0
  84. data/test/integration_test.rb +652 -0
  85. data/test/interpolations_test.rb +219 -0
  86. data/test/iostream_test.rb +71 -0
  87. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  88. data/test/matchers/validate_attachment_content_type_matcher_test.rb +110 -0
  89. data/test/matchers/validate_attachment_presence_matcher_test.rb +47 -0
  90. data/test/matchers/validate_attachment_size_matcher_test.rb +72 -0
  91. data/test/paperclip_missing_attachment_styles_test.rb +96 -0
  92. data/test/paperclip_test.rb +409 -0
  93. data/test/processor_test.rb +10 -0
  94. data/test/schema_test.rb +98 -0
  95. data/test/storage/filesystem_test.rb +62 -0
  96. data/test/storage/fog_test.rb +280 -0
  97. data/test/storage/s3_live_test.rb +138 -0
  98. data/test/storage/s3_test.rb +1093 -0
  99. data/test/style_test.rb +215 -0
  100. data/test/support/mock_attachment.rb +22 -0
  101. data/test/support/mock_interpolator.rb +24 -0
  102. data/test/support/mock_model.rb +2 -0
  103. data/test/support/mock_url_generator_builder.rb +27 -0
  104. data/test/thumbnail_test.rb +396 -0
  105. data/test/upfile_test.rb +53 -0
  106. data/test/url_generator_test.rb +187 -0
  107. metadata +374 -0
@@ -0,0 +1,2 @@
1
+ require 'paperclip/railtie'
2
+ Paperclip::Railtie.insert
@@ -0,0 +1,124 @@
1
+ require 'paperclip/matchers'
2
+
3
+ module Paperclip
4
+ # =Paperclip Shoulda Macros
5
+ #
6
+ # These macros are intended for use with shoulda, and will be included into
7
+ # your tests automatically. All of the macros use the standard shoulda
8
+ # assumption that the name of the test is based on the name of the model
9
+ # you're testing (that is, UserTest is the test for the User model), and
10
+ # will load that class for testing purposes.
11
+ module Shoulda
12
+ include Matchers
13
+ # This will test whether you have defined your attachment correctly by
14
+ # checking for all the required fields exist after the definition of the
15
+ # attachment.
16
+ def should_have_attached_file name
17
+ klass = self.name.gsub(/Test$/, '').constantize
18
+ matcher = have_attached_file name
19
+ should matcher.description do
20
+ assert_accepts(matcher, klass)
21
+ end
22
+ end
23
+
24
+ # Tests for validations on the presence of the attachment.
25
+ def should_validate_attachment_presence name
26
+ klass = self.name.gsub(/Test$/, '').constantize
27
+ matcher = validate_attachment_presence name
28
+ should matcher.description do
29
+ assert_accepts(matcher, klass)
30
+ end
31
+ end
32
+
33
+ # Tests that you have content_type validations specified. There are two
34
+ # options, :valid and :invalid. Both accept an array of strings. The
35
+ # strings should be a list of content types which will pass and fail
36
+ # validation, respectively.
37
+ def should_validate_attachment_content_type name, options = {}
38
+ klass = self.name.gsub(/Test$/, '').constantize
39
+ valid = [options[:valid]].flatten
40
+ invalid = [options[:invalid]].flatten
41
+ matcher = validate_attachment_content_type(name).allowing(valid).rejecting(invalid)
42
+ should matcher.description do
43
+ assert_accepts(matcher, klass)
44
+ end
45
+ end
46
+
47
+ # Tests to ensure that you have file size validations turned on. You
48
+ # can pass the same options to this that you can to
49
+ # validate_attachment_file_size - :less_than, :greater_than, and :in.
50
+ # :less_than checks that a file is less than a certain size, :greater_than
51
+ # checks that a file is more than a certain size, and :in takes a Range or
52
+ # Array which specifies the lower and upper limits of the file size.
53
+ def should_validate_attachment_size name, options = {}
54
+ klass = self.name.gsub(/Test$/, '').constantize
55
+ min = options[:greater_than] || (options[:in] && options[:in].first) || 0
56
+ max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
57
+ range = (min..max)
58
+ matcher = validate_attachment_size(name).in(range)
59
+ should matcher.description do
60
+ assert_accepts(matcher, klass)
61
+ end
62
+ end
63
+
64
+ # Stubs the HTTP PUT for an attachment using S3 storage.
65
+ #
66
+ # @example
67
+ # stub_paperclip_s3('user', 'avatar', 'png')
68
+ def stub_paperclip_s3(model, attachment, extension)
69
+ definition = model.gsub(" ", "_").classify.constantize.
70
+ attachment_definitions[attachment.to_sym]
71
+
72
+ path = "http://s3.amazonaws.com/:id/#{definition[:path]}"
73
+ path.gsub!(/:([^\/\.]+)/) do |match|
74
+ "([^\/\.]+)"
75
+ end
76
+
77
+ begin
78
+ FakeWeb.register_uri(:put, Regexp.new(path), :body => "OK")
79
+ rescue NameError
80
+ raise NameError, "the stub_paperclip_s3 shoulda macro requires the fakeweb gem."
81
+ end
82
+ end
83
+
84
+ # Stub S3 and return a file for attachment. Best with Factory Girl.
85
+ # Uses a strict directory convention:
86
+ #
87
+ # features/support/paperclip
88
+ #
89
+ # This method is used by the Paperclip-provided Cucumber step:
90
+ #
91
+ # When I attach a "demo_tape" "mp3" file to a "band" on S3
92
+ #
93
+ # @example
94
+ # Factory.define :band_with_demo_tape, :parent => :band do |band|
95
+ # band.demo_tape { band.paperclip_fixture("band", "demo_tape", "png") }
96
+ # end
97
+ def paperclip_fixture(model, attachment, extension)
98
+ stub_paperclip_s3(model, attachment, extension)
99
+ base_path = File.join(File.dirname(__FILE__), "..", "..",
100
+ "features", "support", "paperclip")
101
+ File.new(File.join(base_path, model, "#{attachment}.#{extension}"))
102
+ end
103
+ end
104
+ end
105
+
106
+ if defined?(ActionController::Integration::Session)
107
+ class ActionController::Integration::Session #:nodoc:
108
+ include Paperclip::Shoulda
109
+ end
110
+ end
111
+
112
+ if defined?(FactoryGirl::Factory)
113
+ class FactoryGirl::Factory
114
+ include Paperclip::Shoulda #:nodoc:
115
+ end
116
+ else
117
+ class Factory
118
+ include Paperclip::Shoulda #:nodoc:
119
+ end
120
+ end
121
+
122
+ class Test::Unit::TestCase #:nodoc:
123
+ extend Paperclip::Shoulda
124
+ end
@@ -0,0 +1,40 @@
1
+ require './test/helper'
2
+
3
+ class AttachmentOptionsTest < Test::Unit::TestCase
4
+ should "be a Hash" do
5
+ assert_kind_of Hash, Paperclip::AttachmentOptions.new({})
6
+ end
7
+
8
+ should "add a default empty validations" do
9
+ options = {:arbi => :trary}
10
+ expected = {:validations => []}.merge(options)
11
+ actual = Paperclip::AttachmentOptions.new(options).to_hash
12
+ assert_equal expected, actual
13
+ end
14
+
15
+ should "not override validations if passed to initializer" do
16
+ options = {:validations => "something"}
17
+ attachment_options = Paperclip::AttachmentOptions.new(options)
18
+ assert_equal "something", attachment_options[:validations]
19
+ end
20
+
21
+ should "respond to []" do
22
+ assert Paperclip::AttachmentOptions.new({}).respond_to?(:[])
23
+ end
24
+
25
+ should "deliver the specified options through []" do
26
+ intended_options = {:specific_key => "specific value"}
27
+ attachment_options = Paperclip::AttachmentOptions.new(intended_options)
28
+ assert_equal "specific value", attachment_options[:specific_key]
29
+ end
30
+
31
+ should "respond to []=" do
32
+ assert Paperclip::AttachmentOptions.new({}).respond_to?(:[]=)
33
+ end
34
+
35
+ should "remember options set with []=" do
36
+ attachment_options = Paperclip::AttachmentOptions.new({})
37
+ attachment_options[:foo] = "bar"
38
+ assert_equal "bar", attachment_options[:foo]
39
+ end
40
+ end
@@ -0,0 +1,1211 @@
1
+ # encoding: utf-8
2
+ require './test/helper'
3
+ require 'paperclip/attachment'
4
+
5
+ class Dummy; end
6
+
7
+ class AttachmentTest < Test::Unit::TestCase
8
+
9
+ should "process :original style first" do
10
+ file = File.new(File.join(File.dirname(__FILE__), "fixtures", "50x50.png"), 'rb')
11
+ rebuild_class :styles => { :small => '100x>', :original => '42x42#' }
12
+ dummy = Dummy.new
13
+ dummy.avatar = file
14
+ dummy.save
15
+
16
+ # :small avatar should be 42px wide (processed original), not 50px (preprocessed original)
17
+ assert_equal `identify -format "%w" "#{dummy.avatar.path(:small)}"`.strip, "42"
18
+
19
+ file.close
20
+ end
21
+
22
+ should "handle a boolean second argument to #url" do
23
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
24
+ attachment = Paperclip::Attachment.new(:name, :instance, :url_generator => mock_url_generator_builder)
25
+
26
+ attachment.url(:style_name, true)
27
+ assert mock_url_generator_builder.has_generated_url_with_options?(:timestamp => true, :escape => true)
28
+
29
+ attachment.url(:style_name, false)
30
+ assert mock_url_generator_builder.has_generated_url_with_options?(:timestamp => false, :escape => true)
31
+ end
32
+
33
+ should "pass the style and options through to the URL generator on #url" do
34
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
35
+ attachment = Paperclip::Attachment.new(:name, :instance, :url_generator => mock_url_generator_builder)
36
+
37
+ attachment.url(:style_name, :options => :values)
38
+ assert mock_url_generator_builder.has_generated_url_with_options?(:options => :values)
39
+ end
40
+
41
+ should "pass default options through when #url is given one argument" do
42
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
43
+ attachment = Paperclip::Attachment.new(:name,
44
+ :instance,
45
+ :url_generator => mock_url_generator_builder,
46
+ :use_timestamp => true)
47
+
48
+ attachment.url(:style_name)
49
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true, :timestamp => true)
50
+ end
51
+
52
+ should "pass default style and options through when #url is given no arguments" do
53
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
54
+ attachment = Paperclip::Attachment.new(:name,
55
+ :instance,
56
+ :default_style => 'default style',
57
+ :url_generator => mock_url_generator_builder,
58
+ :use_timestamp => true)
59
+
60
+ attachment.url
61
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true, :timestamp => true)
62
+ assert mock_url_generator_builder.has_generated_url_with_style_name?('default style')
63
+ end
64
+
65
+ should "pass the option :timestamp => true if :use_timestamp is true and :timestamp is not passed" do
66
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
67
+ attachment = Paperclip::Attachment.new(:name,
68
+ :instance,
69
+ :url_generator => mock_url_generator_builder,
70
+ :use_timestamp => true)
71
+
72
+ attachment.url(:style_name)
73
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true, :timestamp => true)
74
+ end
75
+
76
+ should "pass the option :timestamp => false if :use_timestamp is false and :timestamp is not passed" do
77
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
78
+ attachment = Paperclip::Attachment.new(:name,
79
+ :instance,
80
+ :url_generator => mock_url_generator_builder,
81
+ :use_timestamp => false)
82
+
83
+ attachment.url(:style_name)
84
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true, :timestamp => false)
85
+ end
86
+
87
+ should "not change the :timestamp if :timestamp is passed" do
88
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
89
+ attachment = Paperclip::Attachment.new(:name,
90
+ :instance,
91
+ :url_generator => mock_url_generator_builder,
92
+ :use_timestamp => false)
93
+
94
+ attachment.url(:style_name, :timestamp => true)
95
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true, :timestamp => true)
96
+ end
97
+
98
+ should "pass the option :escape => true if :escape_url is true and :escape is not passed" do
99
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
100
+ attachment = Paperclip::Attachment.new(:name,
101
+ :instance,
102
+ :url_generator => mock_url_generator_builder,
103
+ :escape_url => true)
104
+
105
+ attachment.url(:style_name)
106
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => true)
107
+ end
108
+
109
+ should "pass the option :escape => false if :escape_url is false and :escape is not passed" do
110
+ mock_url_generator_builder = MockUrlGeneratorBuilder.new
111
+ attachment = Paperclip::Attachment.new(:name,
112
+ :instance,
113
+ :url_generator => mock_url_generator_builder,
114
+ :escape_url => false)
115
+
116
+ attachment.url(:style_name)
117
+ assert mock_url_generator_builder.has_generated_url_with_options?(:escape => false)
118
+ end
119
+
120
+ should "return the path based on the url by default" do
121
+ @attachment = attachment :url => "/:class/:id/:basename"
122
+ @model = @attachment.instance
123
+ @model.id = 1234
124
+ @model.avatar_file_name = "fake.jpg"
125
+ assert_equal "#{Rails.root}/public/fake_models/1234/fake", @attachment.path
126
+ end
127
+
128
+ context "Attachment default_options" do
129
+ setup do
130
+ rebuild_model
131
+ @old_default_options = Paperclip::Attachment.default_options.dup
132
+ @new_default_options = @old_default_options.merge({
133
+ :path => "argle/bargle",
134
+ :url => "fooferon",
135
+ :default_url => "not here.png"
136
+ })
137
+ end
138
+
139
+ teardown do
140
+ Paperclip::Attachment.default_options.merge! @old_default_options
141
+ end
142
+
143
+ should "be overrideable" do
144
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
145
+ @new_default_options.keys.each do |key|
146
+ assert_equal @new_default_options[key],
147
+ Paperclip::Attachment.default_options[key]
148
+ end
149
+ end
150
+
151
+ context "without an Attachment" do
152
+ setup do
153
+ @dummy = Dummy.new
154
+ end
155
+
156
+ should "return false when asked exists?" do
157
+ assert !@dummy.avatar.exists?
158
+ end
159
+ end
160
+
161
+ context "on an Attachment" do
162
+ setup do
163
+ @dummy = Dummy.new
164
+ @attachment = @dummy.avatar
165
+ end
166
+
167
+ Paperclip::Attachment.default_options.keys.each do |key|
168
+ should "be the default_options for #{key}" do
169
+ assert_equal @old_default_options[key],
170
+ @attachment.instance_variable_get("@options")[key],
171
+ key
172
+ end
173
+ end
174
+
175
+ context "when redefined" do
176
+ setup do
177
+ Paperclip::Attachment.default_options.merge!(@new_default_options)
178
+ @dummy = Dummy.new
179
+ @attachment = @dummy.avatar
180
+ end
181
+
182
+ Paperclip::Attachment.default_options.keys.each do |key|
183
+ should "be the new default_options for #{key}" do
184
+ assert_equal @new_default_options[key],
185
+ @attachment.instance_variable_get("@options")[key],
186
+ key
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ context "An attachment with similarly named interpolations" do
194
+ setup do
195
+ rebuild_model :path => ":id.omg/:id-bbq/:idwhat/:id_partition.wtf"
196
+ @dummy = Dummy.new
197
+ @dummy.stubs(:id).returns(1024)
198
+ @file = File.new(File.join(File.dirname(__FILE__),
199
+ "fixtures",
200
+ "5k.png"), 'rb')
201
+ @dummy.avatar = @file
202
+ end
203
+
204
+ teardown { @file.close }
205
+
206
+ should "make sure that they are interpolated correctly" do
207
+ assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path
208
+ end
209
+ end
210
+
211
+ context "An attachment with :timestamp interpolations" do
212
+ setup do
213
+ @file = StringIO.new("...")
214
+ @zone = 'UTC'
215
+ Time.stubs(:zone).returns(@zone)
216
+ @zone_default = 'Eastern Time (US & Canada)'
217
+ Time.stubs(:zone_default).returns(@zone_default)
218
+ end
219
+
220
+ context "using default time zone" do
221
+ setup do
222
+ rebuild_model :path => ":timestamp", :use_default_time_zone => true
223
+ @dummy = Dummy.new
224
+ @dummy.avatar = @file
225
+ end
226
+
227
+ should "return a time in the default zone" do
228
+ assert_equal @dummy.avatar_updated_at.in_time_zone(@zone_default).to_s, @dummy.avatar.path
229
+ end
230
+ end
231
+
232
+ context "using per-thread time zone" do
233
+ setup do
234
+ rebuild_model :path => ":timestamp", :use_default_time_zone => false
235
+ @dummy = Dummy.new
236
+ @dummy.avatar = @file
237
+ end
238
+
239
+ should "return a time in the per-thread zone" do
240
+ assert_equal @dummy.avatar_updated_at.in_time_zone(@zone).to_s, @dummy.avatar.path
241
+ end
242
+ end
243
+ end
244
+
245
+ context "An attachment with :hash interpolations" do
246
+ setup do
247
+ @file = StringIO.new("...")
248
+ end
249
+
250
+ should "raise if no secret is provided" do
251
+ @attachment = attachment :path => ":hash"
252
+ @attachment.assign @file
253
+
254
+ assert_raise ArgumentError do
255
+ @attachment.path
256
+ end
257
+ end
258
+
259
+ context "when secret is set" do
260
+ setup do
261
+ @attachment = attachment :path => ":hash", :hash_secret => "w00t"
262
+ @attachment.stubs(:instance_read).with(:updated_at).returns(Time.at(1234567890))
263
+ @attachment.stubs(:instance_read).with(:file_name).returns("bla.txt")
264
+ @attachment.instance.id = 1234
265
+ @attachment.assign @file
266
+ end
267
+
268
+ should "interpolate the hash data" do
269
+ @attachment.expects(:interpolate).with(@attachment.options[:hash_data],anything).returns("interpolated_stuff")
270
+ @attachment.hash_key
271
+ end
272
+
273
+ should "result in the correct interpolation" do
274
+ assert_equal "fake_models/avatars/1234/original/1234567890", @attachment.send(:interpolate,@attachment.options[:hash_data])
275
+ end
276
+
277
+ should "result in a correct hash" do
278
+ assert_equal "d22b617d1bf10016aa7d046d16427ae203f39fce", @attachment.path
279
+ end
280
+
281
+ should "generate a hash digest with the correct style" do
282
+ OpenSSL::HMAC.expects(:hexdigest).with(anything, anything, "fake_models/avatars/1234/medium/1234567890")
283
+ @attachment.path("medium")
284
+ end
285
+ end
286
+ end
287
+
288
+ context "An attachment with a :rails_env interpolation" do
289
+ setup do
290
+ @rails_env = "blah"
291
+ @id = 1024
292
+ rebuild_model :path => ":rails_env/:id.png"
293
+ @dummy = Dummy.new
294
+ @dummy.stubs(:id).returns(@id)
295
+ @file = StringIO.new(".")
296
+ @dummy.avatar = @file
297
+ Rails.stubs(:env).returns(@rails_env)
298
+ end
299
+
300
+ should "return the proper path" do
301
+ assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path
302
+ end
303
+ end
304
+
305
+ context "An attachment with a default style and an extension interpolation" do
306
+ setup do
307
+ @attachment = attachment :path => ":basename.:extension",
308
+ :styles => { :default => ["100x100", :png] },
309
+ :default_style => :default
310
+ @file = StringIO.new("...")
311
+ @file.stubs(:original_filename).returns("file.jpg")
312
+ end
313
+ should "return the right extension for the path" do
314
+ @attachment.assign(@file)
315
+ assert_equal "file.png", @attachment.path
316
+ end
317
+ end
318
+
319
+ context "An attachment with :convert_options" do
320
+ setup do
321
+ rebuild_model :styles => {
322
+ :thumb => "100x100",
323
+ :large => "400x400"
324
+ },
325
+ :convert_options => {
326
+ :all => "-do_stuff",
327
+ :thumb => "-thumbnailize"
328
+ }
329
+ @dummy = Dummy.new
330
+ @dummy.avatar
331
+ end
332
+
333
+ should "report the correct options when sent #extra_options_for(:thumb)" do
334
+ assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
335
+ end
336
+
337
+ should "report the correct options when sent #extra_options_for(:large)" do
338
+ assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
339
+ end
340
+ end
341
+
342
+ context "An attachment with :source_file_options" do
343
+ setup do
344
+ rebuild_model :styles => {
345
+ :thumb => "100x100",
346
+ :large => "400x400"
347
+ },
348
+ :source_file_options => {
349
+ :all => "-density 400",
350
+ :thumb => "-depth 8"
351
+ }
352
+ @dummy = Dummy.new
353
+ @dummy.avatar
354
+ end
355
+
356
+ should "report the correct options when sent #extra_source_file_options_for(:thumb)" do
357
+ assert_equal "-depth 8 -density 400", @dummy.avatar.send(:extra_source_file_options_for, :thumb), @dummy.avatar.source_file_options.inspect
358
+ end
359
+
360
+ should "report the correct options when sent #extra_source_file_options_for(:large)" do
361
+ assert_equal "-density 400", @dummy.avatar.send(:extra_source_file_options_for, :large)
362
+ end
363
+ end
364
+
365
+ context "An attachment with :only_process" do
366
+ setup do
367
+ rebuild_model :styles => {
368
+ :thumb => "100x100",
369
+ :large => "400x400"
370
+ },
371
+ :only_process => [:thumb]
372
+ @file = StringIO.new("...")
373
+ @attachment = Dummy.new.avatar
374
+ end
375
+
376
+ should "only process the provided style" do
377
+ @attachment.expects(:post_process).with(:thumb)
378
+ @attachment.expects(:post_process).with(:large).never
379
+ @attachment.assign(@file)
380
+ end
381
+ end
382
+
383
+ context "An attachment with :convert_options that is a proc" do
384
+ setup do
385
+ rebuild_model :styles => {
386
+ :thumb => "100x100",
387
+ :large => "400x400"
388
+ },
389
+ :convert_options => {
390
+ :all => lambda{|i| i.all },
391
+ :thumb => lambda{|i| i.thumb }
392
+ }
393
+ Dummy.class_eval do
394
+ def all; "-all"; end
395
+ def thumb; "-thumb"; end
396
+ end
397
+ @dummy = Dummy.new
398
+ @dummy.avatar
399
+ end
400
+
401
+ should "report the correct options when sent #extra_options_for(:thumb)" do
402
+ assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
403
+ end
404
+
405
+ should "report the correct options when sent #extra_options_for(:large)" do
406
+ assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
407
+ end
408
+ end
409
+
410
+ context "An attachment with :path that is a proc" do
411
+ setup do
412
+ rebuild_model :path => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
413
+
414
+ @file = File.new(File.join(File.dirname(__FILE__),
415
+ "fixtures",
416
+ "5k.png"), 'rb')
417
+ @dummyA = Dummy.new(:other => 'a')
418
+ @dummyA.avatar = @file
419
+ @dummyB = Dummy.new(:other => 'b')
420
+ @dummyB.avatar = @file
421
+ end
422
+
423
+ teardown { @file.close }
424
+
425
+ should "return correct path" do
426
+ assert_equal "path/a.png", @dummyA.avatar.path
427
+ assert_equal "path/b.png", @dummyB.avatar.path
428
+ end
429
+ end
430
+
431
+ context "An attachment with :styles that is a proc" do
432
+ setup do
433
+ rebuild_model :styles => lambda{ |attachment| {:thumb => "50x50#", :large => "400x400"} }
434
+
435
+ @attachment = Dummy.new.avatar
436
+ end
437
+
438
+ should "have the correct geometry" do
439
+ assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
440
+ end
441
+ end
442
+
443
+ context "An attachment with conditional :styles that is a proc" do
444
+ setup do
445
+ rebuild_model :styles => lambda{ |attachment| attachment.instance.other == 'a' ? {:thumb => "50x50#"} : {:large => "400x400"} }
446
+
447
+ @dummy = Dummy.new(:other => 'a')
448
+ end
449
+
450
+ should "have the correct styles for the assigned instance values" do
451
+ assert_equal "50x50#", @dummy.avatar.styles[:thumb][:geometry]
452
+ assert_nil @dummy.avatar.styles[:large]
453
+
454
+ @dummy.other = 'b'
455
+
456
+ assert_equal "400x400", @dummy.avatar.styles[:large][:geometry]
457
+ assert_nil @dummy.avatar.styles[:thumb]
458
+ end
459
+ end
460
+
461
+ geometry_specs = [
462
+ [ lambda{|z| "50x50#" }, :png ],
463
+ lambda{|z| "50x50#" },
464
+ { :geometry => lambda{|z| "50x50#" } }
465
+ ]
466
+ geometry_specs.each do |geometry_spec|
467
+ context "An attachment geometry like #{geometry_spec}" do
468
+ setup do
469
+ rebuild_model :styles => { :normal => geometry_spec }
470
+ @attachment = Dummy.new.avatar
471
+ end
472
+
473
+ context "when assigned" do
474
+ setup do
475
+ @file = StringIO.new(".")
476
+ @attachment.assign(@file)
477
+ end
478
+
479
+ should "have the correct geometry" do
480
+ assert_equal "50x50#", @attachment.styles[:normal][:geometry]
481
+ end
482
+ end
483
+ end
484
+ end
485
+
486
+ context "An attachment with both 'normal' and hash-style styles" do
487
+ setup do
488
+ rebuild_model :styles => {
489
+ :normal => ["50x50#", :png],
490
+ :hash => { :geometry => "50x50#", :format => :png }
491
+ }
492
+ @dummy = Dummy.new
493
+ @attachment = @dummy.avatar
494
+ end
495
+
496
+ [:processors, :whiny, :convert_options, :geometry, :format].each do |field|
497
+ should "have the same #{field} field" do
498
+ assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field]
499
+ end
500
+ end
501
+ end
502
+
503
+ context "An attachment with :processors that is a proc" do
504
+ setup do
505
+ class Paperclip::Test < Paperclip::Processor; end
506
+ @file = StringIO.new("...")
507
+ Paperclip::Test.stubs(:make).returns(@file)
508
+
509
+ rebuild_model :styles => { :normal => '' }, :processors => lambda { |a| [ :test ] }
510
+ @attachment = Dummy.new.avatar
511
+ end
512
+
513
+ context "when assigned" do
514
+ setup do
515
+ @attachment.assign(StringIO.new("."))
516
+ end
517
+
518
+ should "have the correct processors" do
519
+ assert_equal [ :test ], @attachment.styles[:normal][:processors]
520
+ end
521
+ end
522
+ end
523
+
524
+ context "An attachment with erroring processor" do
525
+ setup do
526
+ rebuild_model :processor => [:thumbnail], :styles => { :small => '' }, :whiny_thumbnails => true
527
+ @dummy = Dummy.new
528
+ Paperclip::Thumbnail.expects(:make).raises(Paperclip::PaperclipError, "cannot be processed.")
529
+ @file = StringIO.new("...")
530
+ @file.stubs(:to_tempfile).returns(@file)
531
+ @dummy.avatar = @file
532
+ end
533
+
534
+ should "correctly forward processing error message to the instance" do
535
+ @dummy.valid?
536
+ assert_contains @dummy.errors.full_messages, "Avatar cannot be processed."
537
+ end
538
+ end
539
+
540
+ context "An attachment with multiple processors" do
541
+ setup do
542
+ class Paperclip::Test < Paperclip::Processor; end
543
+ @style_params = { :once => {:one => 1, :two => 2} }
544
+ rebuild_model :processors => [:thumbnail, :test], :styles => @style_params
545
+ @dummy = Dummy.new
546
+ @file = StringIO.new("...")
547
+ @file.stubs(:to_tempfile).returns(@file)
548
+ Paperclip::Test.stubs(:make).returns(@file)
549
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
550
+ end
551
+
552
+ context "when assigned" do
553
+ setup { @dummy.avatar = @file }
554
+
555
+ before_should "call #make on all specified processors" do
556
+ Paperclip::Thumbnail.expects(:make).with(any_parameters).returns(@file)
557
+ Paperclip::Test.expects(:make).with(any_parameters).returns(@file)
558
+ end
559
+
560
+ before_should "call #make with the right parameters passed as second argument" do
561
+ expected_params = @style_params[:once].merge({
562
+ :processors => [:thumbnail, :test],
563
+ :whiny => true,
564
+ :convert_options => "",
565
+ :source_file_options => ""
566
+ })
567
+ Paperclip::Thumbnail.expects(:make).with(anything, expected_params, anything).returns(@file)
568
+ end
569
+
570
+ before_should "call #make with attachment passed as third argument" do
571
+ Paperclip::Test.expects(:make).with(anything, anything, @dummy.avatar).returns(@file)
572
+ end
573
+ end
574
+ end
575
+
576
+ should "include the filesystem module when loading the filesystem storage" do
577
+ rebuild_model :storage => :filesystem
578
+ @dummy = Dummy.new
579
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
580
+ end
581
+
582
+ should "include the filesystem module even if capitalization is wrong" do
583
+ rebuild_model :storage => :FileSystem
584
+ @dummy = Dummy.new
585
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
586
+
587
+ rebuild_model :storage => :Filesystem
588
+ @dummy = Dummy.new
589
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
590
+ end
591
+
592
+ should "convert underscored storage name to camelcase" do
593
+ rebuild_model :storage => :not_here
594
+ @dummy = Dummy.new
595
+ exception = assert_raises(Paperclip::StorageMethodNotFound) do
596
+ @dummy.avatar
597
+ end
598
+ assert exception.message.include?("NotHere")
599
+ end
600
+
601
+ should "raise an error if you try to include a storage module that doesn't exist" do
602
+ rebuild_model :storage => :not_here
603
+ @dummy = Dummy.new
604
+ assert_raises(Paperclip::StorageMethodNotFound) do
605
+ @dummy.avatar
606
+ end
607
+ end
608
+
609
+ context "An attachment with styles but no processors defined" do
610
+ setup do
611
+ rebuild_model :processors => [], :styles => {:something => '1'}
612
+ @dummy = Dummy.new
613
+ @file = StringIO.new("...")
614
+ end
615
+ should "raise when assigned to" do
616
+ assert_raises(RuntimeError){ @dummy.avatar = @file }
617
+ end
618
+ end
619
+
620
+ context "An attachment without styles and with no processors defined" do
621
+ setup do
622
+ rebuild_model :processors => [], :styles => {}
623
+ @dummy = Dummy.new
624
+ @file = StringIO.new("...")
625
+ end
626
+ should "not raise when assigned to" do
627
+ @dummy.avatar = @file
628
+ end
629
+ end
630
+
631
+ context "Assigning an attachment with post_process hooks" do
632
+ setup do
633
+ rebuild_class :styles => { :something => "100x100#" }
634
+ Dummy.class_eval do
635
+ before_avatar_post_process :do_before_avatar
636
+ after_avatar_post_process :do_after_avatar
637
+ before_post_process :do_before_all
638
+ after_post_process :do_after_all
639
+ def do_before_avatar; end
640
+ def do_after_avatar; end
641
+ def do_before_all; end
642
+ def do_after_all; end
643
+ end
644
+ @file = StringIO.new(".")
645
+ @file.stubs(:to_tempfile).returns(@file)
646
+ @dummy = Dummy.new
647
+ Paperclip::Thumbnail.stubs(:make).returns(@file)
648
+ @attachment = @dummy.avatar
649
+ end
650
+
651
+ should "call the defined callbacks when assigned" do
652
+ @dummy.expects(:do_before_avatar).with()
653
+ @dummy.expects(:do_after_avatar).with()
654
+ @dummy.expects(:do_before_all).with()
655
+ @dummy.expects(:do_after_all).with()
656
+ Paperclip::Thumbnail.expects(:make).returns(@file)
657
+ @dummy.avatar = @file
658
+ end
659
+
660
+ should "not cancel the processing if a before_post_process returns nil" do
661
+ @dummy.expects(:do_before_avatar).with().returns(nil)
662
+ @dummy.expects(:do_after_avatar).with()
663
+ @dummy.expects(:do_before_all).with().returns(nil)
664
+ @dummy.expects(:do_after_all).with()
665
+ Paperclip::Thumbnail.expects(:make).returns(@file)
666
+ @dummy.avatar = @file
667
+ end
668
+
669
+ should "cancel the processing if a before_post_process returns false" do
670
+ @dummy.expects(:do_before_avatar).never
671
+ @dummy.expects(:do_after_avatar).never
672
+ @dummy.expects(:do_before_all).with().returns(false)
673
+ @dummy.expects(:do_after_all)
674
+ Paperclip::Thumbnail.expects(:make).never
675
+ @dummy.avatar = @file
676
+ end
677
+
678
+ should "cancel the processing if a before_avatar_post_process returns false" do
679
+ @dummy.expects(:do_before_avatar).with().returns(false)
680
+ @dummy.expects(:do_after_avatar)
681
+ @dummy.expects(:do_before_all).with().returns(true)
682
+ @dummy.expects(:do_after_all)
683
+ Paperclip::Thumbnail.expects(:make).never
684
+ @dummy.avatar = @file
685
+ end
686
+ end
687
+
688
+ context "Assigning an attachment" do
689
+ setup do
690
+ rebuild_model :styles => { :something => "100x100#" }
691
+ @file = StringIO.new(".")
692
+ @file.stubs(:original_filename).returns("5k.png\n\n")
693
+ @file.stubs(:content_type).returns("image/png\n\n")
694
+ @file.stubs(:to_tempfile).returns(@file)
695
+ @dummy = Dummy.new
696
+ Paperclip::Thumbnail.expects(:make).returns(@file)
697
+ @attachment = @dummy.avatar
698
+ @dummy.avatar = @file
699
+ end
700
+
701
+ should "strip whitespace from original_filename field" do
702
+ assert_equal "5k.png", @dummy.avatar.original_filename
703
+ end
704
+
705
+ should "strip whitespace from content_type field" do
706
+ assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
707
+ end
708
+ end
709
+
710
+ context "Attachment with strange letters" do
711
+ setup do
712
+ rebuild_model
713
+
714
+ @not_file = mock("not_file")
715
+ @tempfile = mock("tempfile")
716
+ @not_file.stubs(:nil?).returns(false)
717
+ @not_file.expects(:size).returns(10)
718
+ @tempfile.expects(:size).returns(10)
719
+ @not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n")
720
+ @not_file.expects(:content_type).returns("image/png\r\n")
721
+
722
+ @dummy = Dummy.new
723
+ @attachment = @dummy.avatar
724
+ @attachment.expects(:valid_assignment?).with(@not_file).returns(true)
725
+ @attachment.expects(:queue_existing_for_delete)
726
+ @attachment.expects(:post_process)
727
+ @attachment.expects(:to_tempfile).returns(@tempfile)
728
+ @attachment.expects(:generate_fingerprint).with(@tempfile).returns("12345")
729
+ @attachment.expects(:generate_fingerprint).with(@not_file).returns("12345")
730
+ @dummy.avatar = @not_file
731
+ end
732
+
733
+ should "not remove strange letters" do
734
+ assert_equal "sheep_say_bæ.png", @dummy.avatar.original_filename
735
+ end
736
+ end
737
+
738
+ context "Attachment with reserved filename" do
739
+ setup do
740
+ rebuild_model
741
+ @file = StringIO.new(".")
742
+ end
743
+
744
+ context "with default configuration" do
745
+ "&$+,/:;=?@<>[]{}|\^~%# ".split(//).each do |character|
746
+ context "with character #{character}" do
747
+ setup do
748
+ @file.stubs(:original_filename).returns("file#{character}name.png")
749
+ @dummy = Dummy.new
750
+ @dummy.avatar = @file
751
+ end
752
+
753
+ should "convert special character into underscore" do
754
+ assert_equal "file_name.png", @dummy.avatar.original_filename
755
+ end
756
+ end
757
+ end
758
+ end
759
+
760
+ context "with specified regexp replacement" do
761
+ setup do
762
+ @old_defaults = Paperclip::Attachment.default_options.dup
763
+ Paperclip::Attachment.default_options.merge! :restricted_characters => /o/
764
+
765
+ @file.stubs(:original_filename).returns("goood.png")
766
+ @dummy = Dummy.new
767
+ @dummy.avatar = @file
768
+ end
769
+
770
+ teardown do
771
+ Paperclip::Attachment.default_options.merge! @old_defaults
772
+ end
773
+
774
+ should "match and convert that character" do
775
+ assert_equal "g___d.png", @dummy.avatar.original_filename
776
+ end
777
+ end
778
+ end
779
+
780
+ context "Attachment with uppercase extension and a default style" do
781
+ setup do
782
+ @old_defaults = Paperclip::Attachment.default_options.dup
783
+ Paperclip::Attachment.default_options.merge!({
784
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
785
+ })
786
+ FileUtils.rm_rf("tmp")
787
+ rebuild_model
788
+ @instance = Dummy.new
789
+ @instance.stubs(:id).returns 123
790
+
791
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "uppercase.PNG"), 'rb')
792
+
793
+ styles = {:styles => { :large => ["400x400", :jpg],
794
+ :medium => ["100x100", :jpg],
795
+ :small => ["32x32#", :jpg]},
796
+ :default_style => :small}
797
+ @attachment = Paperclip::Attachment.new(:avatar,
798
+ @instance,
799
+ styles)
800
+ now = Time.now
801
+ Time.stubs(:now).returns(now)
802
+ @attachment.assign(@file)
803
+ @attachment.save
804
+ end
805
+
806
+ teardown do
807
+ @file.close
808
+ Paperclip::Attachment.default_options.merge!(@old_defaults)
809
+ end
810
+
811
+ should "should have matching to_s and url methods" do
812
+ file = @attachment.to_file
813
+ assert file
814
+ assert_match @attachment.to_s, @attachment.url
815
+ assert_match @attachment.to_s(:small), @attachment.url(:small)
816
+ file.close
817
+ end
818
+ end
819
+
820
+ context "An attachment" do
821
+ setup do
822
+ @old_defaults = Paperclip::Attachment.default_options.dup
823
+ Paperclip::Attachment.default_options.merge!({
824
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
825
+ })
826
+ FileUtils.rm_rf("tmp")
827
+ rebuild_model
828
+ @instance = Dummy.new
829
+ @instance.stubs(:id).returns 123
830
+ @attachment = Paperclip::Attachment.new(:avatar, @instance)
831
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
832
+ end
833
+
834
+ teardown do
835
+ @file.close
836
+ Paperclip::Attachment.default_options.merge!(@old_defaults)
837
+ end
838
+
839
+ should "raise if there are not the correct columns when you try to assign" do
840
+ @other_attachment = Paperclip::Attachment.new(:not_here, @instance)
841
+ assert_raises(Paperclip::PaperclipError) do
842
+ @other_attachment.assign(@file)
843
+ end
844
+ end
845
+
846
+ should "return nil as path when no file assigned" do
847
+ assert @attachment.to_file.nil?
848
+ assert_equal nil, @attachment.path
849
+ assert_equal nil, @attachment.path(:blah)
850
+ end
851
+
852
+ context "with a file assigned but not saved yet" do
853
+ should "clear out any attached files" do
854
+ @attachment.assign(@file)
855
+ assert !@attachment.queued_for_write.blank?
856
+ @attachment.clear
857
+ assert @attachment.queued_for_write.blank?
858
+ end
859
+ end
860
+
861
+ context "with a file assigned in the database" do
862
+ setup do
863
+ @attachment.stubs(:instance_read).with(:file_name).returns("5k.png")
864
+ @attachment.stubs(:instance_read).with(:content_type).returns("image/png")
865
+ @attachment.stubs(:instance_read).with(:file_size).returns(12345)
866
+ dtnow = DateTime.now
867
+ @now = Time.now
868
+ Time.stubs(:now).returns(@now)
869
+ @attachment.stubs(:instance_read).with(:updated_at).returns(dtnow)
870
+ end
871
+
872
+ should "return the proper path when filename has a single .'s" do
873
+ assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.png"), File.expand_path(@attachment.path)
874
+ end
875
+
876
+ should "return the proper path when filename has multiple .'s" do
877
+ @attachment.stubs(:instance_read).with(:file_name).returns("5k.old.png")
878
+ assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png"), File.expand_path(@attachment.path)
879
+ end
880
+
881
+ context "when expecting three styles" do
882
+ setup do
883
+ styles = {:styles => { :large => ["400x400", :png],
884
+ :medium => ["100x100", :gif],
885
+ :small => ["32x32#", :jpg]}}
886
+ @attachment = Paperclip::Attachment.new(:avatar,
887
+ @instance,
888
+ styles)
889
+ end
890
+
891
+ context "and assigned a file" do
892
+ setup do
893
+ now = Time.now
894
+ Time.stubs(:now).returns(now)
895
+ @attachment.assign(@file)
896
+ end
897
+
898
+ should "be dirty" do
899
+ assert @attachment.dirty?
900
+ end
901
+
902
+ should "set uploaded_file for access beyond the paperclip lifecycle" do
903
+ assert_equal @file, @attachment.uploaded_file
904
+ end
905
+
906
+ context "and saved" do
907
+ setup do
908
+ @attachment.save
909
+ end
910
+
911
+ should "commit the files to disk" do
912
+ [:large, :medium, :small].each do |style|
913
+ io = @attachment.to_file(style)
914
+ # p "in commit to disk test, io is #{io.inspect} and @instance.id is #{@instance.id}"
915
+ assert File.exists?(io.path)
916
+ assert ! io.is_a?(::Tempfile)
917
+ io.close
918
+ end
919
+ end
920
+
921
+ should "save the files as the right formats and sizes" do
922
+ [[:large, 400, 61, "PNG"],
923
+ [:medium, 100, 15, "GIF"],
924
+ [:small, 32, 32, "JPEG"]].each do |style|
925
+ cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"]
926
+ out = `#{cmd}`
927
+ width, height, size, format = out.split(" ")
928
+ assert_equal style[1].to_s, width.to_s
929
+ assert_equal style[2].to_s, height.to_s
930
+ assert_equal style[3].to_s, format.to_s
931
+ end
932
+ end
933
+
934
+ should "still have its #file attribute not be nil" do
935
+ assert ! (file = @attachment.to_file).nil?
936
+ file.close
937
+ end
938
+
939
+ context "and trying to delete" do
940
+ setup do
941
+ @existing_names = @attachment.styles.keys.collect do |style|
942
+ @attachment.path(style)
943
+ end
944
+ end
945
+
946
+ should "delete the files after assigning nil" do
947
+ @attachment.expects(:instance_write).with(:file_name, nil)
948
+ @attachment.expects(:instance_write).with(:content_type, nil)
949
+ @attachment.expects(:instance_write).with(:file_size, nil)
950
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
951
+ @attachment.expects(:instance_write).with(:updated_at, nil)
952
+ @attachment.assign nil
953
+ @attachment.save
954
+ @existing_names.each{|f| assert ! File.exists?(f) }
955
+ end
956
+
957
+ should "delete the files when you call #clear and #save" do
958
+ @attachment.expects(:instance_write).with(:file_name, nil)
959
+ @attachment.expects(:instance_write).with(:content_type, nil)
960
+ @attachment.expects(:instance_write).with(:file_size, nil)
961
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
962
+ @attachment.expects(:instance_write).with(:updated_at, nil)
963
+ @attachment.clear
964
+ @attachment.save
965
+ @existing_names.each{|f| assert ! File.exists?(f) }
966
+ end
967
+
968
+ should "delete the files when you call #delete" do
969
+ @attachment.expects(:instance_write).with(:file_name, nil)
970
+ @attachment.expects(:instance_write).with(:content_type, nil)
971
+ @attachment.expects(:instance_write).with(:file_size, nil)
972
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
973
+ @attachment.expects(:instance_write).with(:updated_at, nil)
974
+ @attachment.destroy
975
+ @existing_names.each{|f| assert ! File.exists?(f) }
976
+ end
977
+
978
+ context "when keeping old files" do
979
+ setup do
980
+ @attachment.options[:keep_old_files] = true
981
+ end
982
+
983
+ should "keep the files after assigning nil" do
984
+ @attachment.expects(:instance_write).with(:file_name, nil)
985
+ @attachment.expects(:instance_write).with(:content_type, nil)
986
+ @attachment.expects(:instance_write).with(:file_size, nil)
987
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
988
+ @attachment.expects(:instance_write).with(:updated_at, nil)
989
+ @attachment.assign nil
990
+ @attachment.save
991
+ @existing_names.each{|f| assert File.exists?(f) }
992
+ end
993
+
994
+ should "keep the files when you call #clear and #save" do
995
+ @attachment.expects(:instance_write).with(:file_name, nil)
996
+ @attachment.expects(:instance_write).with(:content_type, nil)
997
+ @attachment.expects(:instance_write).with(:file_size, nil)
998
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
999
+ @attachment.expects(:instance_write).with(:updated_at, nil)
1000
+ @attachment.clear
1001
+ @attachment.save
1002
+ @existing_names.each{|f| assert File.exists?(f) }
1003
+ end
1004
+
1005
+ should "keep the files when you call #delete" do
1006
+ @attachment.expects(:instance_write).with(:file_name, nil)
1007
+ @attachment.expects(:instance_write).with(:content_type, nil)
1008
+ @attachment.expects(:instance_write).with(:file_size, nil)
1009
+ @attachment.expects(:instance_write).with(:fingerprint, nil)
1010
+ @attachment.expects(:instance_write).with(:updated_at, nil)
1011
+ @attachment.destroy
1012
+ @existing_names.each{|f| assert File.exists?(f) }
1013
+ end
1014
+ end
1015
+ end
1016
+ end
1017
+ end
1018
+ end
1019
+ end
1020
+
1021
+ context "when trying a nonexistant storage type" do
1022
+ setup do
1023
+ rebuild_model :storage => :not_here
1024
+ end
1025
+
1026
+ should "not be able to find the module" do
1027
+ assert_raise(Paperclip::StorageMethodNotFound){ Dummy.new.avatar }
1028
+ end
1029
+ end
1030
+ end
1031
+
1032
+ context "An attachment with only a avatar_file_name column" do
1033
+ setup do
1034
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
1035
+ table.column :avatar_file_name, :string
1036
+ end
1037
+ rebuild_class
1038
+ @dummy = Dummy.new
1039
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
1040
+ end
1041
+
1042
+ teardown { @file.close }
1043
+
1044
+ should "not error when assigned an attachment" do
1045
+ assert_nothing_raised { @dummy.avatar = @file }
1046
+ end
1047
+
1048
+ should "return the time when sent #avatar_updated_at" do
1049
+ now = Time.now
1050
+ Time.stubs(:now).returns(now)
1051
+ @dummy.avatar = @file
1052
+ assert_equal now.to_i, @dummy.avatar.updated_at.to_i
1053
+ end
1054
+
1055
+ should "return nil when reloaded and sent #avatar_updated_at" do
1056
+ @dummy.save
1057
+ @dummy.reload
1058
+ assert_nil @dummy.avatar.updated_at
1059
+ end
1060
+
1061
+ should "return the right value when sent #avatar_file_size" do
1062
+ @dummy.avatar = @file
1063
+ assert_equal @file.size, @dummy.avatar.size
1064
+ end
1065
+
1066
+ context "and avatar_updated_at column" do
1067
+ setup do
1068
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_updated_at, :timestamp
1069
+ rebuild_class
1070
+ @dummy = Dummy.new
1071
+ end
1072
+
1073
+ should "not error when assigned an attachment" do
1074
+ assert_nothing_raised { @dummy.avatar = @file }
1075
+ end
1076
+
1077
+ should "return the right value when sent #avatar_updated_at" do
1078
+ now = Time.now
1079
+ Time.stubs(:now).returns(now)
1080
+ @dummy.avatar = @file
1081
+ assert_equal now.to_i, @dummy.avatar.updated_at
1082
+ end
1083
+ end
1084
+
1085
+ should "not calculate fingerprint after save" do
1086
+ @dummy.avatar = @file
1087
+ @dummy.save
1088
+ assert_nil @dummy.avatar.fingerprint
1089
+ end
1090
+
1091
+ should "not calculate fingerprint before saving" do
1092
+ @dummy.avatar = @file
1093
+ assert_nil @dummy.avatar.fingerprint
1094
+ end
1095
+
1096
+ context "and avatar_content_type column" do
1097
+ setup do
1098
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string
1099
+ rebuild_class
1100
+ @dummy = Dummy.new
1101
+ end
1102
+
1103
+ should "not error when assigned an attachment" do
1104
+ assert_nothing_raised { @dummy.avatar = @file }
1105
+ end
1106
+
1107
+ should "return the right value when sent #avatar_content_type" do
1108
+ @dummy.avatar = @file
1109
+ assert_equal "image/png", @dummy.avatar.content_type
1110
+ end
1111
+ end
1112
+
1113
+ context "and avatar_file_size column" do
1114
+ setup do
1115
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer
1116
+ rebuild_class
1117
+ @dummy = Dummy.new
1118
+ end
1119
+
1120
+ should "not error when assigned an attachment" do
1121
+ assert_nothing_raised { @dummy.avatar = @file }
1122
+ end
1123
+
1124
+ should "return the right value when sent #avatar_file_size" do
1125
+ @dummy.avatar = @file
1126
+ assert_equal @file.size, @dummy.avatar.size
1127
+ end
1128
+
1129
+ should "return the right value when saved, reloaded, and sent #avatar_file_size" do
1130
+ @dummy.avatar = @file
1131
+ @dummy.save
1132
+ @dummy = Dummy.find(@dummy.id)
1133
+ assert_equal @file.size, @dummy.avatar.size
1134
+ end
1135
+ end
1136
+
1137
+ context "and avatar_fingerprint column" do
1138
+ setup do
1139
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_fingerprint, :string
1140
+ rebuild_class
1141
+ @dummy = Dummy.new
1142
+ end
1143
+
1144
+ should "not error when assigned an attachment" do
1145
+ assert_nothing_raised { @dummy.avatar = @file }
1146
+ end
1147
+
1148
+ should "return the right value when sent #avatar_fingerprint" do
1149
+ @dummy.avatar = @file
1150
+ assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
1151
+ end
1152
+
1153
+ should "return the right value when saved, reloaded, and sent #avatar_fingerprint" do
1154
+ @dummy.avatar = @file
1155
+ @dummy.save
1156
+ @dummy = Dummy.find(@dummy.id)
1157
+ assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
1158
+ end
1159
+ end
1160
+ end
1161
+
1162
+ context "an attachment with delete_file option set to false" do
1163
+ setup do
1164
+ rebuild_model :preserve_files => true
1165
+ @dummy = Dummy.new
1166
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
1167
+ @dummy.avatar = @file
1168
+ @dummy.save!
1169
+ @attachment = @dummy.avatar
1170
+ @path = @attachment.path
1171
+ end
1172
+
1173
+ should "not delete the files from storage when attachment is destroyed" do
1174
+ @attachment.destroy
1175
+ assert File.exists?(@path)
1176
+ end
1177
+
1178
+ should "not delete the file when model is destroyed" do
1179
+ @dummy.destroy
1180
+ assert File.exists?(@path)
1181
+ end
1182
+ end
1183
+
1184
+ context "An attached file" do
1185
+ setup do
1186
+ rebuild_model
1187
+ @dummy = Dummy.new
1188
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
1189
+ @dummy.avatar = @file
1190
+ @dummy.save!
1191
+ @attachment = @dummy.avatar
1192
+ @path = @attachment.path
1193
+ end
1194
+
1195
+ should "not be deleted when the model fails to destroy" do
1196
+ @dummy.stubs(:destroy).raises(Exception)
1197
+
1198
+ assert_raise Exception do
1199
+ @dummy.destroy
1200
+ end
1201
+
1202
+ assert File.exists?(@path), "#{@path} does not exist."
1203
+ end
1204
+
1205
+ should "be deleted when the model is destroyed" do
1206
+ @dummy.destroy
1207
+ assert ! File.exists?(@path), "#{@path} does not exist."
1208
+ end
1209
+ end
1210
+
1211
+ end