atd-attachment_fu 1.0.20080507

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/CHANGELOG +35 -0
  2. data/README +186 -0
  3. data/Rakefile +22 -0
  4. data/amazon_s3.yml.tpl +14 -0
  5. data/attachment_fu.gemspec +79 -0
  6. data/lib/geometry.rb +93 -0
  7. data/lib/technoweenie/attachment_fu.rb +497 -0
  8. data/lib/technoweenie/attachment_fu/backends/db_file_backend.rb +39 -0
  9. data/lib/technoweenie/attachment_fu/backends/file_system_backend.rb +101 -0
  10. data/lib/technoweenie/attachment_fu/backends/s3_backend.rb +303 -0
  11. data/lib/technoweenie/attachment_fu/processors/core_image_processor.rb +59 -0
  12. data/lib/technoweenie/attachment_fu/processors/gd2_processor.rb +54 -0
  13. data/lib/technoweenie/attachment_fu/processors/image_science_processor.rb +61 -0
  14. data/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb +132 -0
  15. data/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb +54 -0
  16. data/rails/init.rb +16 -0
  17. data/test/backends/db_file_test.rb +16 -0
  18. data/test/backends/file_system_test.rb +80 -0
  19. data/test/backends/remote/s3_test.rb +119 -0
  20. data/test/base_attachment_tests.rb +77 -0
  21. data/test/basic_test.rb +71 -0
  22. data/test/database.yml +18 -0
  23. data/test/extra_attachment_test.rb +86 -0
  24. data/test/fixtures/attachment.rb +183 -0
  25. data/test/fixtures/files/fake/rails.png +0 -0
  26. data/test/fixtures/files/foo.txt +1 -0
  27. data/test/fixtures/files/rails.png +0 -0
  28. data/test/geometry_test.rb +108 -0
  29. data/test/processors/core_image_test.rb +37 -0
  30. data/test/processors/gd2_test.rb +31 -0
  31. data/test/processors/image_science_test.rb +31 -0
  32. data/test/processors/mini_magick_test.rb +103 -0
  33. data/test/processors/rmagick_test.rb +255 -0
  34. data/test/schema.rb +109 -0
  35. data/test/test_helper.rb +150 -0
  36. data/test/validation_test.rb +55 -0
  37. data/vendor/red_artisan/core_image/filters/color.rb +27 -0
  38. data/vendor/red_artisan/core_image/filters/effects.rb +31 -0
  39. data/vendor/red_artisan/core_image/filters/perspective.rb +25 -0
  40. data/vendor/red_artisan/core_image/filters/quality.rb +25 -0
  41. data/vendor/red_artisan/core_image/filters/scale.rb +47 -0
  42. data/vendor/red_artisan/core_image/filters/watermark.rb +32 -0
  43. data/vendor/red_artisan/core_image/processor.rb +123 -0
  44. metadata +116 -0
@@ -0,0 +1,77 @@
1
+ module BaseAttachmentTests
2
+ def test_should_create_file_from_uploaded_file
3
+ assert_created do
4
+ attachment = upload_file :filename => '/files/foo.txt'
5
+ assert_valid attachment
6
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
7
+ assert attachment.image?
8
+ assert !attachment.size.zero?
9
+ #assert_equal 3, attachment.size
10
+ assert_nil attachment.width
11
+ assert_nil attachment.height
12
+ end
13
+ end
14
+
15
+ def test_should_create_file_from_merb_temp_file
16
+ assert_created do
17
+ attachment = upload_merb_file :filename => '/files/foo.txt'
18
+ assert_valid attachment
19
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
20
+ assert attachment.image?
21
+ assert !attachment.size.zero?
22
+ #assert_equal 3, attachment.size
23
+ assert_nil attachment.width
24
+ assert_nil attachment.height
25
+ end
26
+ end
27
+
28
+ def test_reassign_attribute_data
29
+ assert_created 1 do
30
+ attachment = upload_file :filename => '/files/rails.png'
31
+ assert_valid attachment
32
+ assert attachment.size > 0, "no data was set"
33
+
34
+ attachment.set_temp_data 'wtf'
35
+ assert attachment.save_attachment?
36
+ attachment.save!
37
+
38
+ assert_equal 'wtf', attachment_model.find(attachment.id).send(:current_data)
39
+ end
40
+ end
41
+
42
+ def test_no_reassign_attribute_data_on_nil
43
+ assert_created 1 do
44
+ attachment = upload_file :filename => '/files/rails.png'
45
+ assert_valid attachment
46
+ assert attachment.size > 0, "no data was set"
47
+
48
+ attachment.set_temp_data nil
49
+ assert !attachment.save_attachment?
50
+ end
51
+ end
52
+
53
+ def test_should_overwrite_old_contents_when_updating
54
+ attachment = upload_file :filename => '/files/rails.png'
55
+ assert_not_created do # no new db_file records
56
+ use_temp_file 'files/rails.png' do |file|
57
+ attachment.filename = 'rails2.png'
58
+ attachment.temp_paths.unshift File.join(fixture_path, file)
59
+ attachment.save!
60
+ end
61
+ end
62
+ end
63
+
64
+ def test_should_save_without_updating_file
65
+ attachment = upload_file :filename => '/files/foo.txt'
66
+ assert_valid attachment
67
+ assert !attachment.save_attachment?
68
+ assert_nothing_raised { attachment.save! }
69
+ end
70
+
71
+ def test_should_handle_nil_file_upload
72
+ attachment = attachment_model.create :uploaded_data => ''
73
+ assert_raise ActiveRecord::RecordInvalid do
74
+ attachment.save!
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,71 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class BasicTest < Test::Unit::TestCase
4
+ def test_should_set_default_min_size
5
+ assert_equal 1, Attachment.attachment_options[:min_size]
6
+ end
7
+
8
+ def test_should_set_default_max_size
9
+ assert_equal 1.megabyte, Attachment.attachment_options[:max_size]
10
+ end
11
+
12
+ def test_should_set_default_size
13
+ assert_equal (1..1.megabyte), Attachment.attachment_options[:size]
14
+ end
15
+
16
+ def test_should_set_default_thumbnails_option
17
+ assert_equal Hash.new, Attachment.attachment_options[:thumbnails]
18
+ end
19
+
20
+ def test_should_set_default_thumbnail_class
21
+ assert_equal Attachment, Attachment.attachment_options[:thumbnail_class]
22
+ end
23
+
24
+ def test_should_normalize_content_types_to_array
25
+ assert_equal %w(pdf), PdfAttachment.attachment_options[:content_type]
26
+ assert_equal %w(pdf doc txt), DocAttachment.attachment_options[:content_type]
27
+ assert_equal ['pdf'] + Technoweenie::AttachmentFu::content_types, ImageOrPdfAttachment.attachment_options[:content_type]
28
+ # by default ImageAttachment should just have the default image content_types the module defines
29
+ assert_equal Technoweenie::AttachmentFu::content_types, ImageAttachment.attachment_options[:content_type]
30
+ end
31
+
32
+ def test_should_sanitize_content_type
33
+ @attachment = Attachment.new :content_type => ' foo '
34
+ assert_equal 'foo', @attachment.content_type
35
+ end
36
+
37
+ def test_should_sanitize_filenames
38
+ @attachment = Attachment.new :filename => 'blah/foo.bar'
39
+ assert_equal 'foo.bar', @attachment.filename
40
+
41
+ @attachment.filename = 'blah\\foo.bar'
42
+ assert_equal 'foo.bar', @attachment.filename
43
+
44
+ @attachment.filename = 'f o!O-.bar'
45
+ assert_equal 'f_o_O-.bar', @attachment.filename
46
+
47
+ @attachment.filename = 'sheeps_says_bææ'
48
+ assert_equal 'sheeps_says_b__', @attachment.filename
49
+
50
+ @attachment.filename = nil
51
+ assert_nil @attachment.filename
52
+ end
53
+
54
+ def test_should_convert_thumbnail_name
55
+ @attachment = FileAttachment.new :filename => 'foo.bar'
56
+ assert_equal 'foo.bar', @attachment.thumbnail_name_for(nil)
57
+ assert_equal 'foo.bar', @attachment.thumbnail_name_for('')
58
+ assert_equal 'foo_blah.bar', @attachment.thumbnail_name_for(:blah)
59
+ assert_equal 'foo_blah.blah.bar', @attachment.thumbnail_name_for('blah.blah')
60
+
61
+ @attachment.filename = 'foo.bar.baz'
62
+ assert_equal 'foo.bar_blah.baz', @attachment.thumbnail_name_for(:blah)
63
+ end
64
+
65
+ def test_should_require_valid_thumbnails_option
66
+ klass = Class.new(ActiveRecord::Base)
67
+ assert_raise ArgumentError do
68
+ klass.has_attachment :thumbnails => []
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :dbfile: attachment_fu_plugin.sqlite.db
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :dbfile: 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,86 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class CSVAttachmentTest < Test::Unit::TestCase
4
+ attachment_model SmallAttachment
5
+
6
+ # should deal with blank content_type from safari issues
7
+ def test_should_create_file_from_uploaded_csv_from_safari
8
+ assert_created do
9
+ attachment = upload_file :filename => '/files/foo.csv', :content_type => ""
10
+ assert_equal "text/csv", attachment.content_type
11
+ assert_valid attachment
12
+ end
13
+ end
14
+ end
15
+
16
+ class OrphanAttachmentTest < Test::Unit::TestCase
17
+ include BaseAttachmentTests
18
+ attachment_model OrphanAttachment
19
+
20
+ def test_should_create_image_from_uploaded_file
21
+ assert_created do
22
+ attachment = upload_file :filename => '/files/rails.png'
23
+ assert_valid attachment
24
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
25
+ assert attachment.image?
26
+ assert !attachment.size.zero?
27
+ end
28
+ end
29
+
30
+ def test_should_create_file_from_uploaded_file
31
+ assert_created do
32
+ attachment = upload_file :filename => '/files/foo.txt'
33
+ assert_valid attachment
34
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
35
+ assert attachment.image?
36
+ assert !attachment.size.zero?
37
+ end
38
+ end
39
+
40
+ def test_should_create_file_from_merb_temp_file
41
+ assert_created do
42
+ attachment = upload_merb_file :filename => '/files/foo.txt'
43
+ assert_valid attachment
44
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
45
+ assert attachment.image?
46
+ assert !attachment.size.zero?
47
+ end
48
+ end
49
+
50
+ def test_should_create_image_from_uploaded_file_with_custom_content_type
51
+ assert_created do
52
+ attachment = upload_file :content_type => 'foo/bar', :filename => '/files/rails.png'
53
+ assert_valid attachment
54
+ assert !attachment.image?
55
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
56
+ assert !attachment.size.zero?
57
+ #assert_equal 1784, attachment.size
58
+ end
59
+ end
60
+
61
+ def test_should_create_thumbnail
62
+ attachment = upload_file :filename => '/files/rails.png'
63
+
64
+ assert_raise Technoweenie::AttachmentFu::ThumbnailError do
65
+ attachment.create_or_update_thumbnail(attachment.create_temp_file, 'thumb', 50, 50)
66
+ end
67
+ end
68
+
69
+ def test_should_create_thumbnail_with_geometry_string
70
+ attachment = upload_file :filename => '/files/rails.png'
71
+
72
+ assert_raise Technoweenie::AttachmentFu::ThumbnailError do
73
+ attachment.create_or_update_thumbnail(attachment.create_temp_file, 'thumb', 'x50')
74
+ end
75
+ end
76
+ end
77
+
78
+ class MinimalAttachmentTest < OrphanAttachmentTest
79
+ attachment_model MinimalAttachment
80
+
81
+ def test_should_be_able_to_set_a_random_attribute
82
+ attachment = attachment_model.new(:spare_data => "test")
83
+ assert_equal "test", attachment.spare_data
84
+ end
85
+
86
+ end
@@ -0,0 +1,183 @@
1
+ class Attachment < ActiveRecord::Base
2
+ @@saves = 0
3
+ cattr_accessor :saves
4
+ has_attachment :processor => :rmagick
5
+ validates_as_attachment
6
+ after_attachment_saved do |record|
7
+ self.saves += 1
8
+ end
9
+ end
10
+
11
+ class SmallAttachment < Attachment
12
+ has_attachment :max_size => 1.kilobyte
13
+ end
14
+
15
+ class BigAttachment < Attachment
16
+ has_attachment :size => 1.megabyte..2.megabytes
17
+ end
18
+
19
+ class PdfAttachment < Attachment
20
+ has_attachment :content_type => 'pdf'
21
+ end
22
+
23
+ class DocAttachment < Attachment
24
+ has_attachment :content_type => %w(pdf doc txt)
25
+ end
26
+
27
+ class ImageAttachment < Attachment
28
+ has_attachment :content_type => :image, :resize_to => [50,50]
29
+ end
30
+
31
+ class ImageOrPdfAttachment < Attachment
32
+ has_attachment :content_type => ['pdf', :image], :resize_to => 'x50'
33
+ end
34
+
35
+ class ImageWithThumbsAttachment < Attachment
36
+ has_attachment :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
37
+ after_resize do |record, img|
38
+ # record.aspect_ratio = img.columns.to_f / img.rows.to_f
39
+ end
40
+ end
41
+
42
+ class FileAttachment < ActiveRecord::Base
43
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
44
+ validates_as_attachment
45
+ end
46
+
47
+ class ImageFileAttachment < FileAttachment
48
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
49
+ :content_type => :image, :resize_to => [50,50]
50
+ end
51
+
52
+ class ImageWithThumbsFileAttachment < FileAttachment
53
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
54
+ :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
55
+ after_resize do |record, img|
56
+ # record.aspect_ratio = img.columns.to_f / img.rows.to_f
57
+ end
58
+ end
59
+
60
+ class ImageWithThumbsClassFileAttachment < FileAttachment
61
+ # use file_system_path to test backwards compatibility
62
+ has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files',
63
+ :thumbnails => { :thumb => [50, 50] }, :resize_to => [55,55],
64
+ :thumbnail_class => 'ImageThumbnail'
65
+ end
66
+
67
+ class ImageThumbnail < FileAttachment
68
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files/thumbnails'
69
+ end
70
+
71
+ # no parent
72
+ class OrphanAttachment < ActiveRecord::Base
73
+ has_attachment :processor => :rmagick
74
+ validates_as_attachment
75
+ end
76
+
77
+ # no filename, no size, no content_type
78
+ class MinimalAttachment < ActiveRecord::Base
79
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
80
+ validates_as_attachment
81
+
82
+ def filename
83
+ "#{id}.file"
84
+ end
85
+ end
86
+
87
+ begin
88
+ class ImageScienceAttachment < ActiveRecord::Base
89
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
90
+ :processor => :image_science, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
91
+ end
92
+ rescue MissingSourceFile
93
+ puts $!.message
94
+ puts "no ImageScience"
95
+ end
96
+
97
+ begin
98
+ class CoreImageAttachment < ActiveRecord::Base
99
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
100
+ :processor => :core_image, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
101
+ end
102
+ rescue MissingSourceFile
103
+ puts $!.message
104
+ puts "no CoreImage"
105
+ end
106
+
107
+ begin
108
+ class MiniMagickAttachment < ActiveRecord::Base
109
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
110
+ :processor => :mini_magick, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
111
+ end
112
+ rescue MissingSourceFile
113
+ puts $!.message
114
+ puts "no Mini Magick"
115
+ end
116
+
117
+ begin
118
+ class GD2Attachment < ActiveRecord::Base
119
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
120
+ :processor => :gd2, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
121
+ end
122
+ rescue MissingSourceFile
123
+ puts $!.message
124
+ puts "no GD2"
125
+ end
126
+
127
+
128
+ begin
129
+ class MiniMagickAttachment < ActiveRecord::Base
130
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
131
+ :processor => :mini_magick, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
132
+ end
133
+ class ImageThumbnailCrop < MiniMagickAttachment
134
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
135
+ :thumbnails => { :square => "50x50c", :vertical => "30x60c", :horizontal => "60x30c"}
136
+
137
+ # TODO this is a bad duplication, this method is in the MiniMagick Processor
138
+ def self.calculate_offset(image_width,image_height,image_aspect,thumb_width,thumb_height,thumb_aspect)
139
+ # only crop if image is not smaller in both dimensions
140
+
141
+ # special cases, image smaller in one dimension then thumbsize
142
+ if image_width < thumb_width
143
+ offset = (image_height / 2) - (thumb_height / 2)
144
+ command = "#{image_width}x#{thumb_height}+0+#{offset}"
145
+ elsif image_height < thumb_height
146
+ offset = (image_width / 2) - (thumb_width / 2)
147
+ command = "#{thumb_width}x#{image_height}+#{offset}+0"
148
+
149
+ # normal thumbnail generation
150
+ # calculate height and offset y, width is fixed
151
+ elsif (image_aspect <= thumb_aspect or image_width < thumb_width) and image_height > thumb_height
152
+ height = image_width / thumb_aspect
153
+ offset = (image_height / 2) - (height / 2)
154
+ command = "#{image_width}x#{height}+0+#{offset}"
155
+ # calculate width and offset x, height is fixed
156
+ else
157
+ width = image_height * thumb_aspect
158
+ offset = (image_width / 2) - (width / 2)
159
+ command = "#{width}x#{image_height}+#{offset}+0"
160
+ end
161
+ # crop image
162
+ command
163
+ end
164
+ end
165
+
166
+ rescue MissingSourceFile
167
+ end
168
+
169
+
170
+
171
+ begin
172
+ class S3Attachment < ActiveRecord::Base
173
+ has_attachment :storage => :s3, :processor => :rmagick, :s3_config_path => File.join(File.dirname(__FILE__), '../amazon_s3.yml')
174
+ validates_as_attachment
175
+ end
176
+
177
+ class S3WithPathPrefixAttachment < S3Attachment
178
+ has_attachment :storage => :s3, :path_prefix => 'some/custom/path/prefix', :processor => :rmagick
179
+ validates_as_attachment
180
+ end
181
+ rescue
182
+ puts "S3 error: #{$!}"
183
+ end
@@ -0,0 +1 @@
1
+ foo
@@ -0,0 +1,108 @@
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
+ protected
101
+ def assert_geometry(width, height, values)
102
+ values.each do |geo, result|
103
+ # run twice to verify the Geometry string isn't modified after a run
104
+ geo = Geometry.from_s(geo)
105
+ 2.times { assert_equal result, [width, height] / geo }
106
+ end
107
+ end
108
+ end