miloops-attachment_fu 3.2.5

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 (49) hide show
  1. data/CHANGELOG +63 -0
  2. data/LICENSE +20 -0
  3. data/README +253 -0
  4. data/Rakefile +22 -0
  5. data/amazon_s3.yml.tpl +17 -0
  6. data/install.rb +7 -0
  7. data/lib/geometry.rb +96 -0
  8. data/lib/pothoven-attachment_fu.rb +23 -0
  9. data/lib/technoweenie/attachment_fu.rb +578 -0
  10. data/lib/technoweenie/attachment_fu/backends/cloud_file_backend.rb +211 -0
  11. data/lib/technoweenie/attachment_fu/backends/db_file_backend.rb +39 -0
  12. data/lib/technoweenie/attachment_fu/backends/file_system_backend.rb +126 -0
  13. data/lib/technoweenie/attachment_fu/backends/s3_backend.rb +394 -0
  14. data/lib/technoweenie/attachment_fu/processors/core_image_processor.rb +66 -0
  15. data/lib/technoweenie/attachment_fu/processors/gd2_processor.rb +59 -0
  16. data/lib/technoweenie/attachment_fu/processors/image_science_processor.rb +80 -0
  17. data/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb +142 -0
  18. data/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb +66 -0
  19. data/rackspace_cloudfiles.yml.tpl +14 -0
  20. data/test/backends/db_file_test.rb +16 -0
  21. data/test/backends/file_system_test.rb +143 -0
  22. data/test/backends/remote/cloudfiles_test.rb +102 -0
  23. data/test/backends/remote/s3_test.rb +119 -0
  24. data/test/base_attachment_tests.rb +77 -0
  25. data/test/basic_test.rb +120 -0
  26. data/test/database.yml +18 -0
  27. data/test/extra_attachment_test.rb +67 -0
  28. data/test/fixtures/attachment.rb +304 -0
  29. data/test/fixtures/files/fake/rails.png +0 -0
  30. data/test/fixtures/files/foo.txt +1 -0
  31. data/test/fixtures/files/rails.jpg +0 -0
  32. data/test/fixtures/files/rails.png +0 -0
  33. data/test/geometry_test.rb +114 -0
  34. data/test/processors/core_image_test.rb +58 -0
  35. data/test/processors/gd2_test.rb +51 -0
  36. data/test/processors/image_science_test.rb +54 -0
  37. data/test/processors/mini_magick_test.rb +122 -0
  38. data/test/processors/rmagick_test.rb +272 -0
  39. data/test/schema.rb +136 -0
  40. data/test/test_helper.rb +180 -0
  41. data/test/validation_test.rb +55 -0
  42. data/vendor/red_artisan/core_image/filters/color.rb +27 -0
  43. data/vendor/red_artisan/core_image/filters/effects.rb +31 -0
  44. data/vendor/red_artisan/core_image/filters/perspective.rb +25 -0
  45. data/vendor/red_artisan/core_image/filters/quality.rb +25 -0
  46. data/vendor/red_artisan/core_image/filters/scale.rb +47 -0
  47. data/vendor/red_artisan/core_image/filters/watermark.rb +32 -0
  48. data/vendor/red_artisan/core_image/processor.rb +123 -0
  49. metadata +98 -0
data/test/database.yml ADDED
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :database: attachment_fu_plugin.sqlite.db
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :database: attachment_fu_plugin.sqlite3.db
7
+ postgresql:
8
+ :adapter: postgresql
9
+ :username: postgres
10
+ :password: postgres
11
+ :database: attachment_fu_plugin_test
12
+ :min_messages: ERROR
13
+ mysql:
14
+ :adapter: mysql
15
+ :host: localhost
16
+ :username: rails
17
+ :password:
18
+ :database: attachment_fu_plugin_test
@@ -0,0 +1,67 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class OrphanAttachmentTest < Test::Unit::TestCase
4
+ include BaseAttachmentTests
5
+ attachment_model OrphanAttachment
6
+
7
+ def test_should_create_image_from_uploaded_file
8
+ assert_created do
9
+ attachment = upload_file :filename => '/files/rails.png'
10
+ assert_valid attachment
11
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
12
+ assert attachment.image?
13
+ assert !attachment.size.zero?
14
+ end
15
+ end
16
+
17
+ def test_should_create_file_from_uploaded_file
18
+ assert_created do
19
+ attachment = upload_file :filename => '/files/foo.txt'
20
+ assert_valid attachment
21
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
22
+ assert attachment.image?
23
+ assert !attachment.size.zero?
24
+ end
25
+ end
26
+
27
+ def test_should_create_file_from_merb_temp_file
28
+ assert_created do
29
+ attachment = upload_merb_file :filename => '/files/foo.txt'
30
+ assert_valid attachment
31
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
32
+ assert attachment.image?
33
+ assert !attachment.size.zero?
34
+ end
35
+ end
36
+
37
+ def test_should_create_image_from_uploaded_file_with_custom_content_type
38
+ assert_created do
39
+ attachment = upload_file :content_type => 'foo/bar', :filename => '/files/rails.png'
40
+ assert_valid attachment
41
+ assert !attachment.image?
42
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
43
+ assert !attachment.size.zero?
44
+ #assert_equal 1784, attachment.size
45
+ end
46
+ end
47
+
48
+ def test_should_create_thumbnail
49
+ attachment = upload_file :filename => '/files/rails.png'
50
+
51
+ assert_raise Technoweenie::AttachmentFu::ThumbnailError do
52
+ attachment.create_or_update_thumbnail(attachment.create_temp_file, 'thumb', 50, 50)
53
+ end
54
+ end
55
+
56
+ def test_should_create_thumbnail_with_geometry_string
57
+ attachment = upload_file :filename => '/files/rails.png'
58
+
59
+ assert_raise Technoweenie::AttachmentFu::ThumbnailError do
60
+ attachment.create_or_update_thumbnail(attachment.create_temp_file, 'thumb', 'x50')
61
+ end
62
+ end
63
+ end
64
+
65
+ class MinimalAttachmentTest < OrphanAttachmentTest
66
+ attachment_model MinimalAttachment
67
+ end
@@ -0,0 +1,304 @@
1
+ class Attachment < ActiveRecord::Base
2
+ @@saves = 0
3
+ cattr_accessor :saves
4
+ has_attachment :processor => :rmagick
5
+ validates_as_attachment
6
+ after_save do |record|
7
+ self.saves += 1
8
+ end
9
+ end
10
+
11
+ class LowerQualityAttachment < Attachment
12
+ set_table_name 'attachments'
13
+ has_attachment :resize_to => [55,55], :jpeg_quality => 50
14
+ end
15
+
16
+ class SmallAttachment < Attachment
17
+ has_attachment :max_size => 1.kilobyte
18
+ end
19
+
20
+ class BigAttachment < Attachment
21
+ has_attachment :size => 1.megabyte..2.megabytes
22
+ end
23
+
24
+ class PdfAttachment < Attachment
25
+ has_attachment :content_type => 'pdf'
26
+ end
27
+
28
+ class DocAttachment < Attachment
29
+ has_attachment :content_type => %w(pdf doc txt)
30
+ end
31
+
32
+ class ImageAttachment < Attachment
33
+ has_attachment :content_type => :image, :resize_to => [50,50]
34
+ end
35
+
36
+ class ImageOrPdfAttachment < Attachment
37
+ has_attachment :content_type => ['pdf', :image], :resize_to => 'x50'
38
+ end
39
+
40
+ class ImageWithThumbsAttachment < Attachment
41
+ has_attachment :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
42
+ # after_resize do |record, img|
43
+ # record.aspect_ratio = img.columns.to_f / img.rows.to_f
44
+ # end
45
+ end
46
+
47
+ class ImageWithPerThumbJpegAttachment < Attachment
48
+ has_attachment :resize_to => '500x500!',
49
+ :thumbnails => { :thumb => '50x50!', :large => '300x300!', :avatar => '64x64!' },
50
+ :jpeg_quality => { :thumb => 90, '<5000' => 85, '>=5000' => 75, :large => 0x200 | 75 }
51
+ end
52
+
53
+ class ImageWithPolymorphicThumbsAttachment < Attachment
54
+ belongs_to :imageable, :polymorphic => true
55
+ has_attachment :thumbnails => {
56
+ :thumb => [50, 50],
57
+ :geometry => 'x50',
58
+ :products => { :large_thumb => '169x169!', :zoomed => '500x500>' },
59
+ :editorials => { :fullsize => '150x100>' },
60
+ 'User' => { :avatar => '64x64!' }
61
+ }
62
+ >>>>>>> 33222f02ee9657d0ea9e4654b06cea7ed49cb85b
63
+ end
64
+
65
+ class FileAttachment < ActiveRecord::Base
66
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
67
+ validates_as_attachment
68
+ end
69
+
70
+ class FileAttachmentWithStringId < ActiveRecord::Base
71
+ set_table_name 'file_attachments_with_string_id'
72
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
73
+ validates_as_attachment
74
+
75
+ before_validation :auto_generate_id
76
+ before_save :auto_generate_id
77
+ @@last_id = 0
78
+
79
+ private
80
+ def auto_generate_id
81
+ @@last_id += 1
82
+ self.id = "id_#{@@last_id}"
83
+ end
84
+ end
85
+
86
+ class FileAttachmentWithUuid < ActiveRecord::Base
87
+ set_table_name 'file_attachments_with_string_id'
88
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick, :uuid_primary_key => true
89
+ validates_as_attachment
90
+
91
+ before_validation :auto_generate_id
92
+ before_save :auto_generate_id
93
+ @@last_id = 0
94
+
95
+ private
96
+ def auto_generate_id
97
+ @@last_id += 1
98
+ self.id = "%0127dx" % @@last_id
99
+ end
100
+ end
101
+
102
+ class ImageFileAttachment < FileAttachment
103
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
104
+ :content_type => :image, :resize_to => [50,50]
105
+ end
106
+
107
+ class ImageWithThumbsFileAttachment < FileAttachment
108
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
109
+ :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
110
+ <<<<<<< HEAD
111
+ def after_resize(img)
112
+ self.aspect_ratio = img.columns.to_f / img.rows.to_f
113
+ end
114
+ =======
115
+ # after_resize do |record, img|
116
+ # record.aspect_ratio = img.columns.to_f / img.rows.to_f
117
+ # end
118
+ >>>>>>> 33222f02ee9657d0ea9e4654b06cea7ed49cb85b
119
+ end
120
+
121
+ class ImageWithThumbsClassFileAttachment < FileAttachment
122
+ # use file_system_path to test backwards compatibility
123
+ has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files',
124
+ :thumbnails => { :thumb => [50, 50] }, :resize_to => [55,55],
125
+ :thumbnail_class => 'ImageThumbnail'
126
+ end
127
+
128
+ class ImageThumbnail < FileAttachment
129
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files/thumbnails'
130
+ end
131
+
132
+ # no parent
133
+ class OrphanAttachment < ActiveRecord::Base
134
+ has_attachment :processor => :rmagick
135
+ validates_as_attachment
136
+ end
137
+
138
+ # no filename, no size, no content_type
139
+ class MinimalAttachment < ActiveRecord::Base
140
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
141
+ validates_as_attachment
142
+
143
+ def filename
144
+ "#{id}.file"
145
+ end
146
+ end
147
+
148
+ begin
149
+ class ImageScienceAttachment < ActiveRecord::Base
150
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
151
+ :processor => :image_science, :thumbnails => { :thumb => [50, 51], :geometry => '31>', :aspect => '25x25!' }, :resize_to => 55
152
+ end
153
+
154
+ class ImageScienceLowerQualityAttachment < ActiveRecord::Base
155
+ set_table_name 'image_science_attachments'
156
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
157
+ :processor => :image_science, :thumbnails => { :thumb => [50, 51], :geometry => '31>', :aspect => '25x25!' }, :resize_to => 55,
158
+ :jpeg_quality => 75
159
+ end
160
+
161
+ class ImageScienceWithPerThumbJpegAttachment < ImageScienceAttachment
162
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
163
+ :processor => :image_science,
164
+ :resize_to => '100x100',
165
+ :thumbnails => { :thumb => [50, 50], :editorial => '300x120', :avatar => '64x64!' },
166
+ :jpeg_quality => { :thumb => 90, '<5000' => 80, '>=5000' => 75 }
167
+ end
168
+ rescue MissingSourceFile
169
+ puts $!.message
170
+ puts "no ImageScience"
171
+ end
172
+
173
+ begin
174
+ class CoreImageAttachment < ActiveRecord::Base
175
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
176
+ :processor => :core_image, :thumbnails => { :thumb => [50, 51], :geometry => '31>', :aspect => '25x25!' }, :resize_to => 55
177
+ end
178
+
179
+ class LowerQualityCoreImageAttachment < CoreImageAttachment
180
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
181
+ :processor => :core_image, :thumbnails => { :thumb => [50, 51], :geometry => '31>', :aspect => '25x25!' }, :resize_to => 55,
182
+ :jpeg_quality => 50
183
+ end
184
+
185
+ class CoreImageWithPerThumbJpegAttachment < CoreImageAttachment
186
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
187
+ :processor => :core_image,
188
+ :resize_to => '100x100',
189
+ :thumbnails => { :thumb => [50, 50], :editorial => '300x120', :avatar => '64x64!' },
190
+ :jpeg_quality => { :thumb => 90, '<5000' => 80, '>=5000' => 75 }
191
+ end
192
+ rescue MissingSourceFile
193
+ puts $!.message
194
+ puts "no CoreImage"
195
+ end
196
+
197
+ begin
198
+ class MiniMagickAttachment < ActiveRecord::Base
199
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
200
+ :processor => :mini_magick, :thumbnails => { :thumb => [50, 51], :geometry => '31>', :aspect => '25x25!' }, :resize_to => 55
201
+ end
202
+
203
+ class ImageThumbnailCrop < MiniMagickAttachment
204
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
205
+ :thumbnails => { :square => "50x50c", :vertical => "30x60c", :horizontal => "60x30c"}
206
+
207
+ # TODO this is a bad duplication, this method is in the MiniMagick Processor
208
+ def self.calculate_offset(image_width,image_height,image_aspect,thumb_width,thumb_height,thumb_aspect)
209
+ # only crop if image is not smaller in both dimensions
210
+
211
+ # special cases, image smaller in one dimension then thumbsize
212
+ if image_width < thumb_width
213
+ offset = (image_height / 2) - (thumb_height / 2)
214
+ command = "#{image_width}x#{thumb_height}+0+#{offset}"
215
+ elsif image_height < thumb_height
216
+ offset = (image_width / 2) - (thumb_width / 2)
217
+ command = "#{thumb_width}x#{image_height}+#{offset}+0"
218
+
219
+ # normal thumbnail generation
220
+ # calculate height and offset y, width is fixed
221
+ elsif (image_aspect <= thumb_aspect or image_width < thumb_width) and image_height > thumb_height
222
+ height = image_width / thumb_aspect
223
+ offset = (image_height / 2) - (height / 2)
224
+ command = "#{image_width}x#{height}+0+#{offset}"
225
+ # calculate width and offset x, height is fixed
226
+ else
227
+ width = image_height * thumb_aspect
228
+ offset = (image_width / 2) - (width / 2)
229
+ command = "#{width}x#{image_height}+#{offset}+0"
230
+ end
231
+ # crop image
232
+ command
233
+ end
234
+ end
235
+
236
+ class LowerQualityMiniMagickAttachment < ActiveRecord::Base
237
+ set_table_name 'mini_magick_attachments'
238
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
239
+ :processor => :mini_magick, :thumbnails => { :thumb => [50, 51], :geometry => '31>', :aspect => '25x25!' }, :resize_to => 55,
240
+ :jpeg_quality => 50
241
+ end
242
+
243
+ class MiniMagickWithPerThumbJpegAttachment < MiniMagickAttachment
244
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
245
+ :processor => :mini_magick,
246
+ :resize_to => '100x100',
247
+ :thumbnails => { :thumb => [50, 50], :editorial => '300x120', :avatar => '64x64!' },
248
+ :jpeg_quality => { :thumb => 90, '<5000' => 80, '>=5000' => 75 }
249
+ end
250
+
251
+ rescue MissingSourceFile
252
+ puts $!.message
253
+ puts "no Mini Magick"
254
+ end
255
+
256
+ begin
257
+ class GD2Attachment < ActiveRecord::Base
258
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
259
+ :processor => :gd2, :thumbnails => { :thumb => [50, 51], :geometry => '31>', :aspect => '25x25!' }, :resize_to => 55
260
+ end
261
+
262
+ class LowerQualityGD2Attachment < GD2Attachment
263
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
264
+ :processor => :gd2, :thumbnails => { :thumb => [50, 51], :geometry => '31>', :aspect => '25x25!' }, :resize_to => 55,
265
+ :jpeg_quality => 50
266
+ end
267
+
268
+ class GD2WithPerThumbJpegAttachment < GD2Attachment
269
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
270
+ :processor => :gd2,
271
+ :resize_to => '100x100',
272
+ :thumbnails => { :thumb => [50, 50], :editorial => '300x120', :avatar => '64x64!' },
273
+ :jpeg_quality => { :thumb => 90, '<5000' => 80, '>=5000' => 75 }
274
+ end
275
+ rescue MissingSourceFile
276
+ puts $!.message
277
+ puts "no GD2"
278
+ end
279
+
280
+
281
+ begin
282
+ class S3Attachment < ActiveRecord::Base
283
+ has_attachment :storage => :s3, :processor => :rmagick, :s3_config_path => File.join(File.dirname(__FILE__), '../amazon_s3.yml')
284
+ validates_as_attachment
285
+ end
286
+
287
+ class CloudFilesAttachment < ActiveRecord::Base
288
+ has_attachment :storage => :cloud_files, :processor => :rmagick, :cloudfiles_config_path => File.join(File.dirname(__FILE__), '../rackspace_cloudfiles.yml')
289
+ validates_as_attachment
290
+ end
291
+
292
+ class S3WithPathPrefixAttachment < S3Attachment
293
+ has_attachment :storage => :s3, :path_prefix => 'some/custom/path/prefix', :processor => :rmagick
294
+ validates_as_attachment
295
+ end
296
+
297
+ class CloudFilesWithPathPrefixAttachment < CloudFilesAttachment
298
+ has_attachment :storage => :cloud_files, :path_prefix => 'some/custom/path/prefix', :processor => :rmagick
299
+ validates_as_attachment
300
+ end
301
+
302
+ rescue
303
+ puts "S3 error: #{$!}"
304
+ end
Binary file
@@ -0,0 +1 @@
1
+ foo
Binary file
Binary file
@@ -0,0 +1,114 @@
1
+ require 'test/unit'
2
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/geometry')) unless Object.const_defined?(:Geometry)
3
+
4
+ class GeometryTest < Test::Unit::TestCase
5
+ def test_should_resize
6
+ assert_geometry 50, 64,
7
+ "50x50" => [39, 50],
8
+ "60x60" => [47, 60],
9
+ "100x100" => [78, 100]
10
+ end
11
+
12
+ def test_should_resize_no_width
13
+ assert_geometry 50, 64,
14
+ "x50" => [39, 50],
15
+ "x60" => [47, 60],
16
+ "x100" => [78, 100]
17
+ end
18
+
19
+ def test_should_resize_no_height
20
+ assert_geometry 50, 64,
21
+ "50" => [50, 64],
22
+ "60" => [60, 77],
23
+ "100" => [100, 128]
24
+ end
25
+
26
+ def test_should_resize_no_height_with_x
27
+ assert_geometry 50, 64,
28
+ "50x" => [50, 64],
29
+ "60x" => [60, 77],
30
+ "100x" => [100, 128]
31
+ end
32
+
33
+ def test_should_resize_with_percent
34
+ assert_geometry 50, 64,
35
+ "50x50%" => [25, 32],
36
+ "60x60%" => [30, 38],
37
+ "120x112%" => [60, 72]
38
+ end
39
+
40
+ def test_should_resize_with_percent_and_no_width
41
+ assert_geometry 50, 64,
42
+ "x50%" => [50, 32],
43
+ "x60%" => [50, 38],
44
+ "x112%" => [50, 72]
45
+ end
46
+
47
+ def test_should_resize_with_percent_and_no_height
48
+ assert_geometry 50, 64,
49
+ "50%" => [25, 32],
50
+ "60%" => [30, 38],
51
+ "120%" => [60, 77]
52
+ end
53
+
54
+ def test_should_resize_with_less
55
+ assert_geometry 50, 64,
56
+ "50x50<" => [50, 64],
57
+ "60x60<" => [50, 64],
58
+ "100x100<" => [78, 100],
59
+ "100x112<" => [88, 112],
60
+ "40x70<" => [50, 64]
61
+ end
62
+
63
+ def test_should_resize_with_less_and_no_width
64
+ assert_geometry 50, 64,
65
+ "x50<" => [50, 64],
66
+ "x60<" => [50, 64],
67
+ "x100<" => [78, 100]
68
+ end
69
+
70
+ def test_should_resize_with_less_and_no_height
71
+ assert_geometry 50, 64,
72
+ "50<" => [50, 64],
73
+ "60<" => [60, 77],
74
+ "100<" => [100, 128]
75
+ end
76
+
77
+ def test_should_resize_with_greater
78
+ assert_geometry 50, 64,
79
+ "50x50>" => [39, 50],
80
+ "60x60>" => [47, 60],
81
+ "100x100>" => [50, 64],
82
+ "100x112>" => [50, 64],
83
+ "40x70>" => [40, 51]
84
+ end
85
+
86
+ def test_should_resize_with_greater_and_no_width
87
+ assert_geometry 50, 64,
88
+ "x40>" => [31, 40],
89
+ "x60>" => [47, 60],
90
+ "x100>" => [50, 64]
91
+ end
92
+
93
+ def test_should_resize_with_greater_and_no_height
94
+ assert_geometry 50, 64,
95
+ "40>" => [40, 51],
96
+ "60>" => [50, 64],
97
+ "100>" => [50, 64]
98
+ end
99
+
100
+ def test_should_resize_with_aspect
101
+ assert_geometry 50, 64,
102
+ "35x35!" => [35, 35],
103
+ "70x70!" => [70, 70]
104
+ end
105
+
106
+ protected
107
+ def assert_geometry(width, height, values)
108
+ values.each do |geo, result|
109
+ # run twice to verify the Geometry string isn't modified after a run
110
+ geo = Geometry.from_s(geo)
111
+ 2.times { assert_equal result, [width, height] / geo }
112
+ end
113
+ end
114
+ end