beaucollins-paperclip 2.2.7

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 (44) hide show
  1. data/LICENSE +26 -0
  2. data/README.rdoc +172 -0
  3. data/Rakefile +77 -0
  4. data/generators/paperclip/USAGE +5 -0
  5. data/generators/paperclip/paperclip_generator.rb +27 -0
  6. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  7. data/init.rb +1 -0
  8. data/lib/paperclip.rb +318 -0
  9. data/lib/paperclip/attachment.rb +404 -0
  10. data/lib/paperclip/callback_compatability.rb +33 -0
  11. data/lib/paperclip/geometry.rb +115 -0
  12. data/lib/paperclip/iostream.rb +58 -0
  13. data/lib/paperclip/matchers.rb +4 -0
  14. data/lib/paperclip/matchers/have_attached_file_matcher.rb +49 -0
  15. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +66 -0
  16. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +48 -0
  17. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +83 -0
  18. data/lib/paperclip/processor.rb +48 -0
  19. data/lib/paperclip/storage.rb +236 -0
  20. data/lib/paperclip/thumbnail.rb +70 -0
  21. data/lib/paperclip/upfile.rb +48 -0
  22. data/shoulda_macros/paperclip.rb +68 -0
  23. data/tasks/paperclip_tasks.rake +79 -0
  24. data/test/attachment_test.rb +742 -0
  25. data/test/database.yml +4 -0
  26. data/test/fixtures/12k.png +0 -0
  27. data/test/fixtures/50x50.png +0 -0
  28. data/test/fixtures/5k.png +0 -0
  29. data/test/fixtures/bad.png +1 -0
  30. data/test/fixtures/text.txt +0 -0
  31. data/test/fixtures/twopage.pdf +0 -0
  32. data/test/geometry_test.rb +168 -0
  33. data/test/helper.rb +82 -0
  34. data/test/integration_test.rb +481 -0
  35. data/test/iostream_test.rb +71 -0
  36. data/test/matchers/have_attached_file_matcher_test.rb +21 -0
  37. data/test/matchers/validate_attachment_content_type_matcher_test.rb +30 -0
  38. data/test/matchers/validate_attachment_presence_matcher_test.rb +21 -0
  39. data/test/matchers/validate_attachment_size_matcher_test.rb +50 -0
  40. data/test/paperclip_test.rb +233 -0
  41. data/test/processor_test.rb +10 -0
  42. data/test/storage_test.rb +277 -0
  43. data/test/thumbnail_test.rb +177 -0
  44. metadata +131 -0
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ This is not an image.
File without changes
Binary file
@@ -0,0 +1,168 @@
1
+ require 'test/helper'
2
+
3
+ class GeometryTest < Test::Unit::TestCase
4
+ context "Paperclip::Geometry" do
5
+ should "correctly report its given dimensions" do
6
+ assert @geo = Paperclip::Geometry.new(1024, 768)
7
+ assert_equal 1024, @geo.width
8
+ assert_equal 768, @geo.height
9
+ end
10
+
11
+ should "set height to 0 if height dimension is missing" do
12
+ assert @geo = Paperclip::Geometry.new(1024)
13
+ assert_equal 1024, @geo.width
14
+ assert_equal 0, @geo.height
15
+ end
16
+
17
+ should "set width to 0 if width dimension is missing" do
18
+ assert @geo = Paperclip::Geometry.new(nil, 768)
19
+ assert_equal 0, @geo.width
20
+ assert_equal 768, @geo.height
21
+ end
22
+
23
+ should "be generated from a WxH-formatted string" do
24
+ assert @geo = Paperclip::Geometry.parse("800x600")
25
+ assert_equal 800, @geo.width
26
+ assert_equal 600, @geo.height
27
+ end
28
+
29
+ should "be generated from a xH-formatted string" do
30
+ assert @geo = Paperclip::Geometry.parse("x600")
31
+ assert_equal 0, @geo.width
32
+ assert_equal 600, @geo.height
33
+ end
34
+
35
+ should "be generated from a Wx-formatted string" do
36
+ assert @geo = Paperclip::Geometry.parse("800x")
37
+ assert_equal 800, @geo.width
38
+ assert_equal 0, @geo.height
39
+ end
40
+
41
+ should "be generated from a W-formatted string" do
42
+ assert @geo = Paperclip::Geometry.parse("800")
43
+ assert_equal 800, @geo.width
44
+ assert_equal 0, @geo.height
45
+ end
46
+
47
+ should "ensure the modifier is nil if not present" do
48
+ assert @geo = Paperclip::Geometry.parse("123x456")
49
+ assert_nil @geo.modifier
50
+ end
51
+
52
+ ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod|
53
+ should "ensure the modifier #{mod.inspect} is preserved" do
54
+ assert @geo = Paperclip::Geometry.parse("123x456#{mod}")
55
+ assert_equal mod, @geo.modifier
56
+ assert_equal "123x456#{mod}", @geo.to_s
57
+ end
58
+ end
59
+
60
+ ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod|
61
+ should "ensure the modifier #{mod.inspect} is preserved with no height" do
62
+ assert @geo = Paperclip::Geometry.parse("123x#{mod}")
63
+ assert_equal mod, @geo.modifier
64
+ assert_equal "123#{mod}", @geo.to_s
65
+ end
66
+ end
67
+
68
+ should "make sure the modifier gets passed during transformation_to" do
69
+ assert @src = Paperclip::Geometry.parse("123x456")
70
+ assert @dst = Paperclip::Geometry.parse("123x456>")
71
+ assert_equal "123x456>", @src.transformation_to(@dst).to_s
72
+ end
73
+
74
+ should "generate correct ImageMagick formatting string for W-formatted string" do
75
+ assert @geo = Paperclip::Geometry.parse("800")
76
+ assert_equal "800", @geo.to_s
77
+ end
78
+
79
+ should "generate correct ImageMagick formatting string for Wx-formatted string" do
80
+ assert @geo = Paperclip::Geometry.parse("800x")
81
+ assert_equal "800", @geo.to_s
82
+ end
83
+
84
+ should "generate correct ImageMagick formatting string for xH-formatted string" do
85
+ assert @geo = Paperclip::Geometry.parse("x600")
86
+ assert_equal "x600", @geo.to_s
87
+ end
88
+
89
+ should "generate correct ImageMagick formatting string for WxH-formatted string" do
90
+ assert @geo = Paperclip::Geometry.parse("800x600")
91
+ assert_equal "800x600", @geo.to_s
92
+ end
93
+
94
+ should "be generated from a file" do
95
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
96
+ file = File.new(file, 'rb')
97
+ assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
98
+ assert @geo.height > 0
99
+ assert @geo.width > 0
100
+ end
101
+
102
+ should "be generated from a file path" do
103
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
104
+ assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
105
+ assert @geo.height > 0
106
+ assert @geo.width > 0
107
+ end
108
+
109
+ should "not generate from a bad file" do
110
+ file = "/home/This File Does Not Exist.omg"
111
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
112
+ end
113
+
114
+ [['vertical', 900, 1440, true, false, false, 1440, 900, 0.625],
115
+ ['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333],
116
+ ['square', 100, 100, false, false, true, 100, 100, 1]].each do |args|
117
+ context "performing calculations on a #{args[0]} viewport" do
118
+ setup do
119
+ @geo = Paperclip::Geometry.new(args[1], args[2])
120
+ end
121
+
122
+ should "#{args[3] ? "" : "not"} be vertical" do
123
+ assert_equal args[3], @geo.vertical?
124
+ end
125
+
126
+ should "#{args[4] ? "" : "not"} be horizontal" do
127
+ assert_equal args[4], @geo.horizontal?
128
+ end
129
+
130
+ should "#{args[5] ? "" : "not"} be square" do
131
+ assert_equal args[5], @geo.square?
132
+ end
133
+
134
+ should "report that #{args[6]} is the larger dimension" do
135
+ assert_equal args[6], @geo.larger
136
+ end
137
+
138
+ should "report that #{args[7]} is the smaller dimension" do
139
+ assert_equal args[7], @geo.smaller
140
+ end
141
+
142
+ should "have an aspect ratio of #{args[8]}" do
143
+ assert_in_delta args[8], @geo.aspect, 0.0001
144
+ end
145
+ end
146
+ end
147
+
148
+ [[ [1000, 100], [64, 64], "x64", "64x64+288+0" ],
149
+ [ [100, 1000], [50, 950], "x950", "50x950+22+0" ],
150
+ [ [100, 1000], [50, 25], "50x", "50x25+0+237" ]]. each do |args|
151
+ context "of #{args[0].inspect} and given a Geometry #{args[1].inspect} and sent transform_to" do
152
+ setup do
153
+ @geo = Paperclip::Geometry.new(*args[0])
154
+ @dst = Paperclip::Geometry.new(*args[1])
155
+ @scale, @crop = @geo.transformation_to @dst, true
156
+ end
157
+
158
+ should "be able to return the correct scaling transformation geometry #{args[2]}" do
159
+ assert_equal args[2], @scale
160
+ end
161
+
162
+ should "be able to return the correct crop transformation geometry #{args[3]}" do
163
+ assert_equal args[3], @crop
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,82 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ gem 'thoughtbot-shoulda', ">= 2.9.0"
4
+ require 'shoulda'
5
+ require 'mocha'
6
+ require 'tempfile'
7
+
8
+ gem 'sqlite3-ruby'
9
+
10
+ require 'active_record'
11
+ require 'active_support'
12
+ begin
13
+ require 'ruby-debug'
14
+ rescue LoadError
15
+ puts "ruby-debug not loaded"
16
+ end
17
+
18
+ ROOT = File.join(File.dirname(__FILE__), '..')
19
+ RAILS_ROOT = ROOT
20
+
21
+ $LOAD_PATH << File.join(ROOT, 'lib')
22
+ $LOAD_PATH << File.join(ROOT, 'lib', 'paperclip')
23
+
24
+ require File.join(ROOT, 'lib', 'paperclip.rb')
25
+
26
+ require 'shoulda_macros/paperclip'
27
+
28
+ ENV['RAILS_ENV'] ||= 'test'
29
+
30
+ FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
31
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
32
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
33
+ ActiveRecord::Base.establish_connection(config['test'])
34
+
35
+ def reset_class class_name
36
+ ActiveRecord::Base.send(:include, Paperclip)
37
+ Object.send(:remove_const, class_name) rescue nil
38
+ klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
39
+ klass.class_eval{ include Paperclip }
40
+ klass
41
+ end
42
+
43
+ def reset_table table_name, &block
44
+ block ||= lambda{ true }
45
+ ActiveRecord::Base.connection.create_table :dummies, {:force => true}, &block
46
+ end
47
+
48
+ def modify_table table_name, &block
49
+ ActiveRecord::Base.connection.change_table :dummies, &block
50
+ end
51
+
52
+ def rebuild_model options = {}
53
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
54
+ table.column :other, :string
55
+ table.column :avatar_file_name, :string
56
+ table.column :avatar_content_type, :string
57
+ table.column :avatar_file_size, :integer
58
+ table.column :avatar_updated_at, :datetime
59
+ end
60
+ rebuild_class options
61
+ end
62
+
63
+ def rebuild_class options = {}
64
+ ActiveRecord::Base.send(:include, Paperclip)
65
+ Object.send(:remove_const, "Dummy") rescue nil
66
+ Object.const_set("Dummy", Class.new(ActiveRecord::Base))
67
+ Dummy.class_eval do
68
+ include Paperclip
69
+ has_attached_file :avatar, options
70
+ end
71
+ end
72
+
73
+ def temporary_rails_env(new_env)
74
+ old_env = defined?(RAILS_ENV) ? RAILS_ENV : nil
75
+ silence_warnings do
76
+ Object.const_set("RAILS_ENV", new_env)
77
+ end
78
+ yield
79
+ silence_warnings do
80
+ Object.const_set("RAILS_ENV", old_env)
81
+ end
82
+ end
@@ -0,0 +1,481 @@
1
+ require 'test/helper'
2
+
3
+ class IntegrationTest < Test::Unit::TestCase
4
+ context "Many models at once" do
5
+ setup do
6
+ rebuild_model
7
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
8
+ 300.times do |i|
9
+ Dummy.create! :avatar => @file
10
+ end
11
+ end
12
+
13
+ should "not exceed the open file limit" do
14
+ assert_nothing_raised do
15
+ dummies = Dummy.find(:all)
16
+ dummies.each { |dummy| dummy.avatar }
17
+ end
18
+ end
19
+ end
20
+
21
+ context "An attachment" do
22
+ setup do
23
+ rebuild_model :styles => { :thumb => "50x50#" }
24
+ @dummy = Dummy.new
25
+ @file = File.new(File.join(File.dirname(__FILE__),
26
+ "fixtures",
27
+ "5k.png"), 'rb')
28
+ @dummy.avatar = @file
29
+ assert @dummy.save
30
+ end
31
+
32
+ teardown { @file.close }
33
+
34
+ should "create its thumbnails properly" do
35
+ assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
36
+ end
37
+
38
+ context "redefining its attachment styles" do
39
+ setup do
40
+ Dummy.class_eval do
41
+ has_attached_file :avatar, :styles => { :thumb => "150x25#" }
42
+ has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } }
43
+ end
44
+ @d2 = Dummy.find(@dummy.id)
45
+ @d2.avatar.reprocess!
46
+ @d2.save
47
+ end
48
+
49
+ should "create its thumbnails properly" do
50
+ assert_match /\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
51
+ assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"`
52
+ end
53
+ end
54
+ end
55
+
56
+ context "A model that modifies its original" do
57
+ setup do
58
+ rebuild_model :styles => { :original => "2x2#" }
59
+ @dummy = Dummy.new
60
+ @file = File.new(File.join(File.dirname(__FILE__),
61
+ "fixtures",
62
+ "5k.png"), 'rb')
63
+ @dummy.avatar = @file
64
+ end
65
+
66
+ should "report the file size of the processed file and not the original" do
67
+ assert_not_equal @file.size, @dummy.avatar.size
68
+ end
69
+
70
+ teardown { @file.close }
71
+ end
72
+
73
+ context "A model with attachments scoped under an id" do
74
+ setup do
75
+ rebuild_model :styles => { :large => "100x100",
76
+ :medium => "50x50" },
77
+ :path => ":rails_root/tmp/:id/:attachments/:style.:extension"
78
+ @dummy = Dummy.new
79
+ @file = File.new(File.join(File.dirname(__FILE__),
80
+ "fixtures",
81
+ "5k.png"), 'rb')
82
+ @dummy.avatar = @file
83
+ end
84
+
85
+ teardown { @file.close }
86
+
87
+ context "when saved" do
88
+ setup do
89
+ @dummy.save
90
+ @saved_path = @dummy.avatar.path(:large)
91
+ end
92
+
93
+ should "have a large file in the right place" do
94
+ assert File.exists?(@dummy.avatar.path(:large))
95
+ end
96
+
97
+ context "and deleted" do
98
+ setup do
99
+ @dummy.avatar.clear
100
+ @dummy.save
101
+ end
102
+
103
+ should "not have a large file in the right place anymore" do
104
+ assert ! File.exists?(@saved_path)
105
+ end
106
+
107
+ should "not have its next two parent directories" do
108
+ assert ! File.exists?(File.dirname(@saved_path))
109
+ assert ! File.exists?(File.dirname(File.dirname(@saved_path)))
110
+ end
111
+
112
+ before_should "not die if an unexpected SystemCallError happens" do
113
+ FileUtils.stubs(:rmdir).raises(Errno::EPIPE)
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ context "A model with no attachment validation" do
120
+ setup do
121
+ rebuild_model :styles => { :large => "300x300>",
122
+ :medium => "100x100",
123
+ :thumb => ["32x32#", :gif] },
124
+ :default_style => :medium,
125
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
126
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
127
+ @dummy = Dummy.new
128
+ end
129
+
130
+ should "have its definition return false when asked about whiny_thumbnails" do
131
+ assert ! Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
132
+ end
133
+
134
+ context "when validates_attachment_thumbnails is called" do
135
+ setup do
136
+ Dummy.validates_attachment_thumbnails :avatar
137
+ end
138
+
139
+ should "have its definition return true when asked about whiny_thumbnails" do
140
+ assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
141
+ end
142
+ end
143
+
144
+ context "redefined to have attachment validations" do
145
+ setup do
146
+ rebuild_model :styles => { :large => "300x300>",
147
+ :medium => "100x100",
148
+ :thumb => ["32x32#", :gif] },
149
+ :whiny_thumbnails => true,
150
+ :default_style => :medium,
151
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
152
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
153
+ end
154
+
155
+ should "have its definition return true when asked about whiny_thumbnails" do
156
+ assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
157
+ end
158
+ end
159
+ end
160
+
161
+ context "A model with no convert_options setting" do
162
+ setup do
163
+ rebuild_model :styles => { :large => "300x300>",
164
+ :medium => "100x100",
165
+ :thumb => ["32x32#", :gif] },
166
+ :default_style => :medium,
167
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
168
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
169
+ @dummy = Dummy.new
170
+ end
171
+
172
+ should "have its definition return nil when asked about convert_options" do
173
+ assert ! Dummy.attachment_definitions[:avatar][:convert_options]
174
+ end
175
+
176
+ context "redefined to have convert_options setting" do
177
+ setup do
178
+ rebuild_model :styles => { :large => "300x300>",
179
+ :medium => "100x100",
180
+ :thumb => ["32x32#", :gif] },
181
+ :convert_options => "-strip -depth 8",
182
+ :default_style => :medium,
183
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
184
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
185
+ end
186
+
187
+ should "have its definition return convert_options value when asked about convert_options" do
188
+ assert_equal "-strip -depth 8", Dummy.attachment_definitions[:avatar][:convert_options]
189
+ end
190
+ end
191
+ end
192
+
193
+ context "A model with a filesystem attachment" do
194
+ setup do
195
+ rebuild_model :styles => { :large => "300x300>",
196
+ :medium => "100x100",
197
+ :thumb => ["32x32#", :gif] },
198
+ :whiny_thumbnails => true,
199
+ :default_style => :medium,
200
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
201
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
202
+ @dummy = Dummy.new
203
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
204
+ @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb')
205
+
206
+ assert @dummy.avatar = @file
207
+ assert @dummy.valid?
208
+ assert @dummy.save
209
+ end
210
+
211
+ should "write and delete its files" do
212
+ [["434x66", :original],
213
+ ["300x46", :large],
214
+ ["100x15", :medium],
215
+ ["32x32", :thumb]].each do |geo, style|
216
+ cmd = %Q[identify -format "%wx%h" "#{@dummy.avatar.path(style)}"]
217
+ assert_equal geo, `#{cmd}`.chomp, cmd
218
+ end
219
+
220
+ saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) }
221
+
222
+ @d2 = Dummy.find(@dummy.id)
223
+ assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path}"`.chomp
224
+ assert_equal "434x66", `identify -format "%wx%h" "#{@d2.avatar.path(:original)}"`.chomp
225
+ assert_equal "300x46", `identify -format "%wx%h" "#{@d2.avatar.path(:large)}"`.chomp
226
+ assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp
227
+ assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp
228
+
229
+ @dummy.avatar = "not a valid file but not nil"
230
+ assert_equal File.basename(@file.path), @dummy.avatar_file_name
231
+ assert @dummy.valid?
232
+ assert @dummy.save
233
+
234
+ saved_paths.each do |p|
235
+ assert File.exists?(p)
236
+ end
237
+
238
+ @dummy.avatar.clear
239
+ assert_nil @dummy.avatar_file_name
240
+ assert @dummy.valid?
241
+ assert @dummy.save
242
+
243
+ saved_paths.each do |p|
244
+ assert ! File.exists?(p)
245
+ end
246
+
247
+ @d2 = Dummy.find(@dummy.id)
248
+ assert_nil @d2.avatar_file_name
249
+ end
250
+
251
+ should "work exactly the same when new as when reloaded" do
252
+ @d2 = Dummy.find(@dummy.id)
253
+
254
+ assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
255
+ [:thumb, :medium, :large, :original].each do |style|
256
+ assert_equal @dummy.avatar.path(style), @d2.avatar.path(style)
257
+ end
258
+
259
+ saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) }
260
+
261
+ @d2.avatar.clear
262
+ assert @d2.save
263
+
264
+ saved_paths.each do |p|
265
+ assert ! File.exists?(p)
266
+ end
267
+ end
268
+
269
+ should "know the difference between good files, bad files, and not files" do
270
+ expected = @dummy.avatar.to_file
271
+ @dummy.avatar = "not a file"
272
+ assert @dummy.valid?
273
+ assert_equal expected.path, @dummy.avatar.path
274
+ expected.close
275
+
276
+ @dummy.avatar = @bad_file
277
+ assert ! @dummy.valid?
278
+ end
279
+
280
+ should "know the difference between good files, bad files, and not files when validating" do
281
+ Dummy.validates_attachment_presence :avatar
282
+ @d2 = Dummy.find(@dummy.id)
283
+ @d2.avatar = @file
284
+ assert @d2.valid?, @d2.errors.full_messages.inspect
285
+ @d2.avatar = @bad_file
286
+ assert ! @d2.valid?
287
+ end
288
+
289
+ should "be able to reload without saving and not have the file disappear" do
290
+ @dummy.avatar = @file
291
+ assert @dummy.save
292
+ @dummy.avatar.clear
293
+ assert_nil @dummy.avatar_file_name
294
+ @dummy.reload
295
+ assert_equal "5k.png", @dummy.avatar_file_name
296
+ end
297
+
298
+ context "that is assigned its file from another Paperclip attachment" do
299
+ setup do
300
+ @dummy2 = Dummy.new
301
+ @file2 = File.new(File.join(FIXTURES_DIR, "12k.png"), 'rb')
302
+ assert @dummy2.avatar = @file2
303
+ @dummy2.save
304
+ end
305
+
306
+ should "work when assigned a file" do
307
+ assert_not_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
308
+ `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
309
+
310
+ assert @dummy.avatar = @dummy2.avatar
311
+ @dummy.save
312
+ assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
313
+ `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
314
+ end
315
+ end
316
+
317
+ end
318
+
319
+ context "A model with an attachments association and a Paperclip attachment" do
320
+ setup do
321
+ Dummy.class_eval do
322
+ has_many :attachments, :class_name => 'Dummy'
323
+ end
324
+
325
+ @dummy = Dummy.new
326
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__),
327
+ "fixtures",
328
+ "5k.png"), 'rb')
329
+ end
330
+
331
+ should "should not error when saving" do
332
+ assert_nothing_raised do
333
+ @dummy.save!
334
+ end
335
+ end
336
+ end
337
+
338
+ if ENV['S3_TEST_BUCKET']
339
+ def s3_files_for attachment
340
+ [:thumb, :medium, :large, :original].inject({}) do |files, style|
341
+ data = `curl "#{attachment.url(style)}" 2>/dev/null`.chomp
342
+ t = Tempfile.new("paperclip-test")
343
+ t.binmode
344
+ t.write(data)
345
+ t.rewind
346
+ files[style] = t
347
+ files
348
+ end
349
+ end
350
+
351
+ def s3_headers_for attachment, style
352
+ `curl --head "#{attachment.url(style)}" 2>/dev/null`.split("\n").inject({}) do |h,head|
353
+ split_head = head.chomp.split(/\s*:\s*/, 2)
354
+ h[split_head.first.downcase] = split_head.last unless split_head.empty?
355
+ h
356
+ end
357
+ end
358
+
359
+ context "A model with an S3 attachment" do
360
+ setup do
361
+ rebuild_model :styles => { :large => "300x300>",
362
+ :medium => "100x100",
363
+ :thumb => ["32x32#", :gif] },
364
+ :storage => :s3,
365
+ :whiny_thumbnails => true,
366
+ # :s3_options => {:logger => Logger.new(StringIO.new)},
367
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")),
368
+ :default_style => :medium,
369
+ :bucket => ENV['S3_TEST_BUCKET'],
370
+ :path => ":class/:attachment/:id/:style/:basename.:extension"
371
+ @dummy = Dummy.new
372
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
373
+ @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb')
374
+
375
+ assert @dummy.avatar = @file
376
+ assert @dummy.valid?
377
+ assert @dummy.save
378
+
379
+ @files_on_s3 = s3_files_for @dummy.avatar
380
+ end
381
+
382
+ should "write and delete its files" do
383
+ [["434x66", :original],
384
+ ["300x46", :large],
385
+ ["100x15", :medium],
386
+ ["32x32", :thumb]].each do |geo, style|
387
+ cmd = %Q[identify -format "%wx%h" "#{@files_on_s3[style].path}"]
388
+ assert_equal geo, `#{cmd}`.chomp, cmd
389
+ end
390
+
391
+ @d2 = Dummy.find(@dummy.id)
392
+ @d2_files = s3_files_for @d2.avatar
393
+ [["434x66", :original],
394
+ ["300x46", :large],
395
+ ["100x15", :medium],
396
+ ["32x32", :thumb]].each do |geo, style|
397
+ cmd = %Q[identify -format "%wx%h" "#{@d2_files[style].path}"]
398
+ assert_equal geo, `#{cmd}`.chomp, cmd
399
+ end
400
+
401
+ @dummy.avatar = "not a valid file but not nil"
402
+ assert_equal File.basename(@file.path), @dummy.avatar_file_name
403
+ assert @dummy.valid?
404
+ assert @dummy.save
405
+
406
+ saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) }
407
+
408
+ saved_keys.each do |key|
409
+ assert key.exists?
410
+ end
411
+
412
+ @dummy.avatar.clear
413
+ assert_nil @dummy.avatar_file_name
414
+ assert @dummy.valid?
415
+ assert @dummy.save
416
+
417
+ saved_keys.each do |key|
418
+ assert ! key.exists?
419
+ end
420
+
421
+ @d2 = Dummy.find(@dummy.id)
422
+ assert_nil @d2.avatar_file_name
423
+ end
424
+
425
+ should "work exactly the same when new as when reloaded" do
426
+ @d2 = Dummy.find(@dummy.id)
427
+
428
+ assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
429
+ [:thumb, :medium, :large, :original].each do |style|
430
+ assert_equal @dummy.avatar.to_file(style).to_s, @d2.avatar.to_file(style).to_s
431
+ end
432
+
433
+ saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) }
434
+
435
+ @d2.avatar.clear
436
+ assert @d2.save
437
+
438
+ saved_keys.each do |key|
439
+ assert ! key.exists?
440
+ end
441
+ end
442
+
443
+ should "know the difference between good files, bad files, not files, and nil" do
444
+ expected = @dummy.avatar.to_file
445
+ @dummy.avatar = "not a file"
446
+ assert @dummy.valid?
447
+ assert_equal expected.full_name, @dummy.avatar.to_file.full_name
448
+
449
+ @dummy.avatar = @bad_file
450
+ assert ! @dummy.valid?
451
+ @dummy.avatar = nil
452
+ assert @dummy.valid?
453
+
454
+ Dummy.validates_attachment_presence :avatar
455
+ @d2 = Dummy.find(@dummy.id)
456
+ @d2.avatar = @file
457
+ assert @d2.valid?
458
+ @d2.avatar = @bad_file
459
+ assert ! @d2.valid?
460
+ @d2.avatar = nil
461
+ assert ! @d2.valid?
462
+ end
463
+
464
+ should "be able to reload without saving and not have the file disappear" do
465
+ @dummy.avatar = @file
466
+ assert @dummy.save
467
+ @dummy.avatar = nil
468
+ assert_nil @dummy.avatar_file_name
469
+ @dummy.reload
470
+ assert_equal "5k.png", @dummy.avatar_file_name
471
+ end
472
+
473
+ should "have the right content type" do
474
+ headers = s3_headers_for(@dummy.avatar, :original)
475
+ p headers
476
+ assert_equal 'image/png', headers['content-type']
477
+ end
478
+ end
479
+ end
480
+ end
481
+