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,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.
@@ -0,0 +1,8 @@
1
+ development:
2
+ provider: AWS
3
+ aws_access_key_id: AWS_ID
4
+ aws_secret_access_key: AWS_SECRET
5
+ test:
6
+ provider: AWS
7
+ aws_access_key_id: AWS_ID
8
+ aws_secret_access_key: AWS_SECRET
@@ -0,0 +1,8 @@
1
+ development:
2
+ key: 54321
3
+ production:
4
+ key: 12345
5
+ test:
6
+ bucket: <%= ENV['S3_BUCKET'] %>
7
+ access_key_id: <%= ENV['S3_KEY'] %>
8
+ secret_access_key: <%= ENV['S3_SECRET'] %>
@@ -0,0 +1 @@
1
+ paperclip!
Binary file
@@ -0,0 +1,206 @@
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
+ should "treat x and X the same in geometries" do
53
+ @lower = Paperclip::Geometry.parse("123x456")
54
+ @upper = Paperclip::Geometry.parse("123X456")
55
+ assert_equal 123, @lower.width
56
+ assert_equal 123, @upper.width
57
+ assert_equal 456, @lower.height
58
+ assert_equal 456, @upper.height
59
+ end
60
+
61
+ ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod|
62
+ should "ensure the modifier #{mod.inspect} is preserved" do
63
+ assert @geo = Paperclip::Geometry.parse("123x456#{mod}")
64
+ assert_equal mod, @geo.modifier
65
+ assert_equal "123x456#{mod}", @geo.to_s
66
+ end
67
+ end
68
+
69
+ ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod|
70
+ should "ensure the modifier #{mod.inspect} is preserved with no height" do
71
+ assert @geo = Paperclip::Geometry.parse("123x#{mod}")
72
+ assert_equal mod, @geo.modifier
73
+ assert_equal "123#{mod}", @geo.to_s
74
+ end
75
+ end
76
+
77
+ should "make sure the modifier gets passed during transformation_to" do
78
+ assert @src = Paperclip::Geometry.parse("123x456")
79
+ assert @dst = Paperclip::Geometry.parse("123x456>")
80
+ assert_equal ["123x456>", nil], @src.transformation_to(@dst)
81
+ end
82
+
83
+ should "generate correct ImageMagick formatting string for W-formatted string" do
84
+ assert @geo = Paperclip::Geometry.parse("800")
85
+ assert_equal "800", @geo.to_s
86
+ end
87
+
88
+ should "generate correct ImageMagick formatting string for Wx-formatted string" do
89
+ assert @geo = Paperclip::Geometry.parse("800x")
90
+ assert_equal "800", @geo.to_s
91
+ end
92
+
93
+ should "generate correct ImageMagick formatting string for xH-formatted string" do
94
+ assert @geo = Paperclip::Geometry.parse("x600")
95
+ assert_equal "x600", @geo.to_s
96
+ end
97
+
98
+ should "generate correct ImageMagick formatting string for WxH-formatted string" do
99
+ assert @geo = Paperclip::Geometry.parse("800x600")
100
+ assert_equal "800x600", @geo.to_s
101
+ end
102
+
103
+ should "be generated from a file" do
104
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
105
+ file = File.new(file, 'rb')
106
+ assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
107
+ assert @geo.height > 0
108
+ assert @geo.width > 0
109
+ end
110
+
111
+ should "be generated from a file path" do
112
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
113
+ assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
114
+ assert @geo.height > 0
115
+ assert @geo.width > 0
116
+ end
117
+
118
+ should "not generate from a bad file" do
119
+ file = "/home/This File Does Not Exist.omg"
120
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
121
+ end
122
+
123
+ should "not generate from a blank filename" do
124
+ file = ""
125
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
126
+ end
127
+
128
+ should "not generate from a nil file" do
129
+ file = nil
130
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
131
+ end
132
+
133
+ should "not generate from a file with no path" do
134
+ file = mock("file", :path => "")
135
+ file.stubs(:respond_to?).with(:path).returns(true)
136
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
137
+ end
138
+
139
+ should "let us know when a command isn't found versus a processing error" do
140
+ old_path = ENV['PATH']
141
+ begin
142
+ ENV['PATH'] = ''
143
+ assert_raises(Paperclip::CommandNotFoundError) do
144
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
145
+ @geo = Paperclip::Geometry.from_file(file)
146
+ end
147
+ ensure
148
+ ENV['PATH'] = old_path
149
+ end
150
+ end
151
+
152
+ [['vertical', 900, 1440, true, false, false, 1440, 900, 0.625],
153
+ ['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333],
154
+ ['square', 100, 100, false, false, true, 100, 100, 1]].each do |args|
155
+ context "performing calculations on a #{args[0]} viewport" do
156
+ setup do
157
+ @geo = Paperclip::Geometry.new(args[1], args[2])
158
+ end
159
+
160
+ should "#{args[3] ? "" : "not"} be vertical" do
161
+ assert_equal args[3], @geo.vertical?
162
+ end
163
+
164
+ should "#{args[4] ? "" : "not"} be horizontal" do
165
+ assert_equal args[4], @geo.horizontal?
166
+ end
167
+
168
+ should "#{args[5] ? "" : "not"} be square" do
169
+ assert_equal args[5], @geo.square?
170
+ end
171
+
172
+ should "report that #{args[6]} is the larger dimension" do
173
+ assert_equal args[6], @geo.larger
174
+ end
175
+
176
+ should "report that #{args[7]} is the smaller dimension" do
177
+ assert_equal args[7], @geo.smaller
178
+ end
179
+
180
+ should "have an aspect ratio of #{args[8]}" do
181
+ assert_in_delta args[8], @geo.aspect, 0.0001
182
+ end
183
+ end
184
+ end
185
+
186
+ [[ [1000, 100], [64, 64], "x64", "64x64+288+0" ],
187
+ [ [100, 1000], [50, 950], "x950", "50x950+22+0" ],
188
+ [ [100, 1000], [50, 25], "50x", "50x25+0+237" ]]. each do |args|
189
+ context "of #{args[0].inspect} and given a Geometry #{args[1].inspect} and sent transform_to" do
190
+ setup do
191
+ @geo = Paperclip::Geometry.new(*args[0])
192
+ @dst = Paperclip::Geometry.new(*args[1])
193
+ @scale, @crop = @geo.transformation_to @dst, true
194
+ end
195
+
196
+ should "be able to return the correct scaling transformation geometry #{args[2]}" do
197
+ assert_equal args[2], @scale
198
+ end
199
+
200
+ should "be able to return the correct crop transformation geometry #{args[3]}" do
201
+ assert_equal args[3], @crop
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,181 @@
1
+ require 'rubygems'
2
+ require 'tempfile'
3
+ require 'pathname'
4
+ require 'test/unit'
5
+
6
+ require 'shoulda'
7
+ require 'mocha'
8
+
9
+ require 'active_record'
10
+ require 'active_record/version'
11
+ require 'active_support'
12
+ require 'mime/types'
13
+ require 'pathname'
14
+
15
+ require 'pathname'
16
+
17
+ puts "Testing against version #{ActiveRecord::VERSION::STRING}"
18
+
19
+ `ruby -e 'exit 0'` # Prime $? with a value.
20
+
21
+ begin
22
+ require 'ruby-debug'
23
+ rescue LoadError => e
24
+ puts "debugger disabled"
25
+ end
26
+
27
+ ROOT = Pathname(File.expand_path(File.join(File.dirname(__FILE__), '..')))
28
+
29
+ def silence_warnings
30
+ old_verbose, $VERBOSE = $VERBOSE, nil
31
+ yield
32
+ ensure
33
+ $VERBOSE = old_verbose
34
+ end
35
+
36
+ class Test::Unit::TestCase
37
+ def setup
38
+ silence_warnings do
39
+ Object.const_set(:Rails, stub('Rails', :root => ROOT, :env => 'test'))
40
+ end
41
+ end
42
+ end
43
+
44
+ $LOAD_PATH << File.join(ROOT, 'lib')
45
+ $LOAD_PATH << File.join(ROOT, 'lib', 'paperclip')
46
+
47
+ require File.join(ROOT, 'lib', 'paperclip.rb')
48
+
49
+ require './shoulda_macros/paperclip'
50
+
51
+ FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
52
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
53
+ ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.dirname(__FILE__) + "/debug.log")
54
+ ActiveRecord::Base.establish_connection(config['test'])
55
+ Paperclip.options[:logger] = ActiveRecord::Base.logger
56
+
57
+ def require_everything_in_directory(directory_name)
58
+ Dir[File.join(File.dirname(__FILE__), directory_name, '*')].each do |f|
59
+ require f
60
+ end
61
+ end
62
+
63
+ require_everything_in_directory('support')
64
+
65
+ def reset_class class_name
66
+ ActiveRecord::Base.send(:include, Paperclip::Glue)
67
+ Object.send(:remove_const, class_name) rescue nil
68
+ klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
69
+ klass.class_eval{ include Paperclip::Glue }
70
+ klass
71
+ end
72
+
73
+ def reset_table table_name, &block
74
+ block ||= lambda { |table| true }
75
+ ActiveRecord::Base.connection.create_table :dummies, {:force => true}, &block
76
+ end
77
+
78
+ def modify_table table_name, &block
79
+ ActiveRecord::Base.connection.change_table :dummies, &block
80
+ end
81
+
82
+ def rebuild_model options = {}
83
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
84
+ table.column :title, :string
85
+ table.column :other, :string
86
+ table.column :avatar_file_name, :string
87
+ table.column :avatar_content_type, :string
88
+ table.column :avatar_file_size, :integer
89
+ table.column :avatar_updated_at, :datetime
90
+ table.column :avatar_fingerprint, :string
91
+ end
92
+ rebuild_class options
93
+ end
94
+
95
+ def rebuild_class options = {}
96
+ ActiveRecord::Base.send(:include, Paperclip::Glue)
97
+ Object.send(:remove_const, "Dummy") rescue nil
98
+ Object.const_set("Dummy", Class.new(ActiveRecord::Base))
99
+ Paperclip.reset_duplicate_clash_check!
100
+ Dummy.class_eval do
101
+ include Paperclip::Glue
102
+ has_attached_file :avatar, options
103
+ end
104
+ Dummy.reset_column_information
105
+ end
106
+
107
+ class FakeModel
108
+ attr_accessor :avatar_file_name,
109
+ :avatar_file_size,
110
+ :avatar_updated_at,
111
+ :avatar_content_type,
112
+ :avatar_fingerprint,
113
+ :id
114
+
115
+ def errors
116
+ @errors ||= []
117
+ end
118
+
119
+ def run_paperclip_callbacks name, *args
120
+ end
121
+
122
+ end
123
+
124
+ def attachment options
125
+ Paperclip::Attachment.new(:avatar, FakeModel.new, options)
126
+ end
127
+
128
+ def silence_warnings
129
+ old_verbose, $VERBOSE = $VERBOSE, nil
130
+ yield
131
+ ensure
132
+ $VERBOSE = old_verbose
133
+ end
134
+
135
+ def should_accept_dummy_class
136
+ should "accept the class" do
137
+ assert_accepts @matcher, @dummy_class
138
+ end
139
+
140
+ should "accept an instance of that class" do
141
+ assert_accepts @matcher, @dummy_class.new
142
+ end
143
+ end
144
+
145
+ def should_reject_dummy_class
146
+ should "reject the class" do
147
+ assert_rejects @matcher, @dummy_class
148
+ end
149
+
150
+ should "reject an instance of that class" do
151
+ assert_rejects @matcher, @dummy_class.new
152
+ end
153
+ end
154
+
155
+ def with_exitstatus_returning(code)
156
+ saved_exitstatus = $?.nil? ? 0 : $?.exitstatus
157
+ begin
158
+ `ruby -e 'exit #{code.to_i}'`
159
+ yield
160
+ ensure
161
+ `ruby -e 'exit #{saved_exitstatus.to_i}'`
162
+ end
163
+ end
164
+
165
+ def fixture_file(filename)
166
+ File.join(File.dirname(__FILE__), 'fixtures', filename)
167
+ end
168
+
169
+ def assert_success_response(url)
170
+ Net::HTTP.get_response(URI.parse(url)) do |response|
171
+ assert_equal "200", response.code,
172
+ "Expected HTTP response code 200, got #{response.code}"
173
+ end
174
+ end
175
+
176
+ def assert_not_found_response(url)
177
+ Net::HTTP.get_response(URI.parse(url)) do |response|
178
+ assert_equal "404", response.code,
179
+ "Expected HTTP response code 404, got #{response.code}"
180
+ end
181
+ end
@@ -0,0 +1,652 @@
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 'reprocessing with unreadable original' do
39
+ setup { File.chmod(0000, @dummy.avatar.path) }
40
+
41
+ should "not raise an error" do
42
+ assert_nothing_raised do
43
+ @dummy.avatar.reprocess!
44
+ end
45
+ end
46
+
47
+ should "return false" do
48
+ assert ! @dummy.avatar.reprocess!
49
+ end
50
+
51
+ teardown { File.chmod(0644, @dummy.avatar.path) }
52
+ end
53
+
54
+ context "redefining its attachment styles" do
55
+ setup do
56
+ Dummy.class_eval do
57
+ has_attached_file :avatar, :styles => { :thumb => "150x25#" }
58
+ has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } }
59
+ end
60
+ @d2 = Dummy.find(@dummy.id)
61
+ @original_timestamp = @d2.avatar_updated_at
62
+ @d2.avatar.reprocess!
63
+ @d2.save
64
+ end
65
+
66
+ should "create its thumbnails properly" do
67
+ assert_match /\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
68
+ assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"`
69
+ end
70
+
71
+ should "change the timestamp" do
72
+ assert_not_equal @original_timestamp, @d2.avatar_updated_at
73
+ end
74
+
75
+ should "clean up the old original if it is a tempfile" do
76
+ original = @d2.avatar.to_file(:original)
77
+ tf = Paperclip::Tempfile.new('original')
78
+ tf.binmode
79
+ original.binmode
80
+ tf.write(original.read)
81
+ original.close
82
+ tf.rewind
83
+
84
+ @d2.avatar.expects(:to_file).with(:original).returns(tf)
85
+
86
+ @d2.avatar.reprocess!
87
+ end
88
+ end
89
+ end
90
+
91
+ context "Attachment" do
92
+ setup do
93
+ @thumb_path = "./test/../public/system/avatars/1/thumb/5k.png"
94
+ File.delete(@thumb_path) if File.exists?(@thumb_path)
95
+ rebuild_model :styles => { :thumb => "50x50#" }
96
+ @dummy = Dummy.new
97
+ @file = File.new(File.join(File.dirname(__FILE__),
98
+ "fixtures",
99
+ "5k.png"), 'rb')
100
+
101
+ end
102
+
103
+ teardown { @file.close }
104
+
105
+ should "not create the thumbnails upon saving when post-processing is disabled" do
106
+ @dummy.avatar.post_processing = false
107
+ @dummy.avatar = @file
108
+ assert @dummy.save
109
+ assert !File.exists?(@thumb_path)
110
+ end
111
+
112
+ should "create the thumbnails upon saving when post_processing is enabled" do
113
+ @dummy.avatar.post_processing = true
114
+ @dummy.avatar = @file
115
+ assert @dummy.save
116
+ assert File.exists?(@thumb_path)
117
+ end
118
+ end
119
+
120
+ context "Attachment with no generated thumbnails" do
121
+ setup do
122
+ @thumb_small_path = "./test/../public/system/avatars/1/thumb_small/5k.png"
123
+ @thumb_large_path = "./test/../public/system/avatars/1/thumb_large/5k.png"
124
+ File.delete(@thumb_small_path) if File.exists?(@thumb_small_path)
125
+ File.delete(@thumb_large_path) if File.exists?(@thumb_large_path)
126
+ rebuild_model :styles => { :thumb_small => "50x50#", :thumb_large => "60x60#" }
127
+ @dummy = Dummy.new
128
+ @file = File.new(File.join(File.dirname(__FILE__),
129
+ "fixtures",
130
+ "5k.png"), 'rb')
131
+
132
+ @dummy.avatar.post_processing = false
133
+ @dummy.avatar = @file
134
+ assert @dummy.save
135
+ @dummy.avatar.post_processing = true
136
+ end
137
+
138
+ teardown { @file.close }
139
+
140
+ should "allow us to create all thumbnails in one go" do
141
+ assert !File.exists?(@thumb_small_path)
142
+ assert !File.exists?(@thumb_large_path)
143
+
144
+ @dummy.avatar.reprocess!
145
+
146
+ assert File.exists?(@thumb_small_path)
147
+ assert File.exists?(@thumb_large_path)
148
+ end
149
+
150
+ should "allow us to selectively create each thumbnail" do
151
+ assert !File.exists?(@thumb_small_path)
152
+ assert !File.exists?(@thumb_large_path)
153
+
154
+ @dummy.avatar.reprocess! :thumb_small
155
+ assert File.exists?(@thumb_small_path)
156
+ assert !File.exists?(@thumb_large_path)
157
+
158
+ @dummy.avatar.reprocess! :thumb_large
159
+ assert File.exists?(@thumb_large_path)
160
+ end
161
+ end
162
+
163
+ context "A model that modifies its original" do
164
+ setup do
165
+ rebuild_model :styles => { :original => "2x2#" }
166
+ @dummy = Dummy.new
167
+ @file = File.new(File.join(File.dirname(__FILE__),
168
+ "fixtures",
169
+ "5k.png"), 'rb')
170
+ @dummy.avatar = @file
171
+ end
172
+
173
+ should "report the file size of the processed file and not the original" do
174
+ assert_not_equal @file.size, @dummy.avatar.size
175
+ end
176
+
177
+ teardown { @file.close }
178
+ end
179
+
180
+ context "A model with attachments scoped under an id" do
181
+ setup do
182
+ rebuild_model :styles => { :large => "100x100",
183
+ :medium => "50x50" },
184
+ :path => ":rails_root/tmp/:id/:attachments/:style.:extension"
185
+ @dummy = Dummy.new
186
+ @file = File.new(File.join(File.dirname(__FILE__),
187
+ "fixtures",
188
+ "5k.png"), 'rb')
189
+ @dummy.avatar = @file
190
+ end
191
+
192
+ teardown { @file.close }
193
+
194
+ context "when saved" do
195
+ setup do
196
+ @dummy.save
197
+ @saved_path = @dummy.avatar.path(:large)
198
+ end
199
+
200
+ should "have a large file in the right place" do
201
+ assert File.exists?(@dummy.avatar.path(:large))
202
+ end
203
+
204
+ context "and deleted" do
205
+ setup do
206
+ @dummy.avatar.clear
207
+ @dummy.save
208
+ end
209
+
210
+ should "not have a large file in the right place anymore" do
211
+ assert ! File.exists?(@saved_path)
212
+ end
213
+
214
+ should "not have its next two parent directories" do
215
+ assert ! File.exists?(File.dirname(@saved_path))
216
+ assert ! File.exists?(File.dirname(File.dirname(@saved_path)))
217
+ end
218
+
219
+ before_should "not die if an unexpected SystemCallError happens" do
220
+ FileUtils.stubs(:rmdir).raises(Errno::EPIPE)
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ context "A model with no attachment validation" do
227
+ setup do
228
+ rebuild_model :styles => { :large => "300x300>",
229
+ :medium => "100x100",
230
+ :thumb => ["32x32#", :gif] },
231
+ :default_style => :medium,
232
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
233
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
234
+ @dummy = Dummy.new
235
+ end
236
+
237
+ should "have its definition return false when asked about whiny_thumbnails" do
238
+ assert ! Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
239
+ end
240
+
241
+ context "when validates_attachment_thumbnails is called" do
242
+ setup do
243
+ Dummy.validates_attachment_thumbnails :avatar
244
+ end
245
+
246
+ should "have its definition return true when asked about whiny_thumbnails" do
247
+ assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
248
+ end
249
+ end
250
+
251
+ context "redefined to have attachment validations" do
252
+ setup do
253
+ rebuild_model :styles => { :large => "300x300>",
254
+ :medium => "100x100",
255
+ :thumb => ["32x32#", :gif] },
256
+ :whiny_thumbnails => true,
257
+ :default_style => :medium,
258
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
259
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
260
+ end
261
+
262
+ should "have its definition return true when asked about whiny_thumbnails" do
263
+ assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails]
264
+ end
265
+ end
266
+ end
267
+
268
+ context "A model with no convert_options setting" do
269
+ setup do
270
+ rebuild_model :styles => { :large => "300x300>",
271
+ :medium => "100x100",
272
+ :thumb => ["32x32#", :gif] },
273
+ :default_style => :medium,
274
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
275
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
276
+ @dummy = Dummy.new
277
+ end
278
+
279
+ should "have its definition return nil when asked about convert_options" do
280
+ assert ! Dummy.attachment_definitions[:avatar][:convert_options]
281
+ end
282
+
283
+ context "redefined to have convert_options setting" do
284
+ setup do
285
+ rebuild_model :styles => { :large => "300x300>",
286
+ :medium => "100x100",
287
+ :thumb => ["32x32#", :gif] },
288
+ :convert_options => "-strip -depth 8",
289
+ :default_style => :medium,
290
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
291
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
292
+ end
293
+
294
+ should "have its definition return convert_options value when asked about convert_options" do
295
+ assert_equal "-strip -depth 8", Dummy.attachment_definitions[:avatar][:convert_options]
296
+ end
297
+ end
298
+ end
299
+
300
+ context "A model with no source_file_options setting" do
301
+ setup do
302
+ rebuild_model :styles => { :large => "300x300>",
303
+ :medium => "100x100",
304
+ :thumb => ["32x32#", :gif] },
305
+ :default_style => :medium,
306
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
307
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
308
+ @dummy = Dummy.new
309
+ end
310
+
311
+ should "have its definition return nil when asked about source_file_options" do
312
+ assert ! Dummy.attachment_definitions[:avatar][:source_file_options]
313
+ end
314
+
315
+ context "redefined to have source_file_options setting" do
316
+ setup do
317
+ rebuild_model :styles => { :large => "300x300>",
318
+ :medium => "100x100",
319
+ :thumb => ["32x32#", :gif] },
320
+ :source_file_options => "-density 400",
321
+ :default_style => :medium,
322
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
323
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
324
+ end
325
+
326
+ should "have its definition return source_file_options value when asked about source_file_options" do
327
+ assert_equal "-density 400", Dummy.attachment_definitions[:avatar][:source_file_options]
328
+ end
329
+ end
330
+ end
331
+
332
+ context "A model with a filesystem attachment" do
333
+ setup do
334
+ rebuild_model :styles => { :large => "300x300>",
335
+ :medium => "100x100",
336
+ :thumb => ["32x32#", :gif] },
337
+ :whiny_thumbnails => true,
338
+ :default_style => :medium,
339
+ :url => "/:attachment/:class/:style/:id/:basename.:extension",
340
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
341
+ @dummy = Dummy.new
342
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
343
+ @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb')
344
+
345
+ assert @dummy.avatar = @file
346
+ assert @dummy.valid?, @dummy.errors.full_messages.join(", ")
347
+ assert @dummy.save
348
+ end
349
+
350
+ should "write and delete its files" do
351
+ [["434x66", :original],
352
+ ["300x46", :large],
353
+ ["100x15", :medium],
354
+ ["32x32", :thumb]].each do |geo, style|
355
+ cmd = %Q[identify -format "%wx%h" "#{@dummy.avatar.path(style)}"]
356
+ assert_equal geo, `#{cmd}`.chomp, cmd
357
+ end
358
+
359
+ saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) }
360
+
361
+ @d2 = Dummy.find(@dummy.id)
362
+ assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path}"`.chomp
363
+ assert_equal "434x66", `identify -format "%wx%h" "#{@d2.avatar.path(:original)}"`.chomp
364
+ assert_equal "300x46", `identify -format "%wx%h" "#{@d2.avatar.path(:large)}"`.chomp
365
+ assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp
366
+ assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp
367
+
368
+ @dummy.avatar = "not a valid file but not nil"
369
+ assert_equal File.basename(@file.path), @dummy.avatar_file_name
370
+ assert @dummy.valid?
371
+ assert @dummy.save
372
+
373
+ saved_paths.each do |p|
374
+ assert File.exists?(p)
375
+ end
376
+
377
+ @dummy.avatar.clear
378
+ assert_nil @dummy.avatar_file_name
379
+ assert @dummy.valid?
380
+ assert @dummy.save
381
+
382
+ saved_paths.each do |p|
383
+ assert ! File.exists?(p)
384
+ end
385
+
386
+ @d2 = Dummy.find(@dummy.id)
387
+ assert_nil @d2.avatar_file_name
388
+ end
389
+
390
+ should "work exactly the same when new as when reloaded" do
391
+ @d2 = Dummy.find(@dummy.id)
392
+
393
+ assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
394
+ [:thumb, :medium, :large, :original].each do |style|
395
+ assert_equal @dummy.avatar.path(style), @d2.avatar.path(style)
396
+ end
397
+
398
+ saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) }
399
+
400
+ @d2.avatar.clear
401
+ assert @d2.save
402
+
403
+ saved_paths.each do |p|
404
+ assert ! File.exists?(p)
405
+ end
406
+ end
407
+
408
+ should "know the difference between good files, bad files, and not files" do
409
+ expected = @dummy.avatar.to_file
410
+ @dummy.avatar = "not a file"
411
+ assert @dummy.valid?
412
+ assert_equal expected.path, @dummy.avatar.path
413
+ expected.close
414
+
415
+ @dummy.avatar = @bad_file
416
+ assert ! @dummy.valid?
417
+ end
418
+
419
+ should "know the difference between good files, bad files, and not files when validating" do
420
+ Dummy.validates_attachment_presence :avatar
421
+ @d2 = Dummy.find(@dummy.id)
422
+ @d2.avatar = @file
423
+ assert @d2.valid?, @d2.errors.full_messages.inspect
424
+ @d2.avatar = @bad_file
425
+ assert ! @d2.valid?
426
+ end
427
+
428
+ should "be able to reload without saving and not have the file disappear" do
429
+ @dummy.avatar = @file
430
+ assert @dummy.save
431
+ @dummy.avatar.clear
432
+ assert_nil @dummy.avatar_file_name
433
+ @dummy.reload
434
+ assert_equal "5k.png", @dummy.avatar_file_name
435
+ end
436
+
437
+ [000,002,022].each do |umask|
438
+ context "when the umask is #{umask}" do
439
+ setup do
440
+ @umask = File.umask umask
441
+ end
442
+
443
+ teardown do
444
+ File.umask @umask
445
+ end
446
+
447
+ should "respect the current umask" do
448
+ @dummy.avatar = @file
449
+ @dummy.save
450
+ assert_equal 0666&~umask, 0666&File.stat(@dummy.avatar.path).mode
451
+ end
452
+ end
453
+ end
454
+
455
+ context "that is assigned its file from another Paperclip attachment" do
456
+ setup do
457
+ @dummy2 = Dummy.new
458
+ @file2 = File.new(File.join(FIXTURES_DIR, "12k.png"), 'rb')
459
+ assert @dummy2.avatar = @file2
460
+ @dummy2.save
461
+ end
462
+
463
+ should "work when assigned a file" do
464
+ assert_not_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
465
+ `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
466
+
467
+ assert @dummy.avatar = @dummy2.avatar
468
+ @dummy.save
469
+ assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
470
+ `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
471
+ assert_equal @dummy.avatar_file_name, @dummy2.avatar_file_name
472
+ end
473
+ end
474
+
475
+ end
476
+
477
+ context "A model with an attachments association and a Paperclip attachment" do
478
+ setup do
479
+ Dummy.class_eval do
480
+ has_many :attachments, :class_name => 'Dummy'
481
+ end
482
+
483
+ @dummy = Dummy.new
484
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__),
485
+ "fixtures",
486
+ "5k.png"), 'rb')
487
+ end
488
+
489
+ should "should not error when saving" do
490
+ assert_nothing_raised do
491
+ @dummy.save!
492
+ end
493
+ end
494
+ end
495
+
496
+ if ENV['S3_TEST_BUCKET']
497
+ def s3_files_for attachment
498
+ [:thumb, :medium, :large, :original].inject({}) do |files, style|
499
+ data = `curl "#{attachment.url(style)}" 2>/dev/null`.chomp
500
+ t = Tempfile.new("paperclip-test")
501
+ t.binmode
502
+ t.write(data)
503
+ t.rewind
504
+ files[style] = t
505
+ files
506
+ end
507
+ end
508
+
509
+ def s3_headers_for attachment, style
510
+ `curl --head "#{attachment.url(style)}" 2>/dev/null`.split("\n").inject({}) do |h,head|
511
+ split_head = head.chomp.split(/\s*:\s*/, 2)
512
+ h[split_head.first.downcase] = split_head.last unless split_head.empty?
513
+ h
514
+ end
515
+ end
516
+
517
+ context "A model with an S3 attachment" do
518
+ setup do
519
+ rebuild_model :styles => { :large => "300x300>",
520
+ :medium => "100x100",
521
+ :thumb => ["32x32#", :gif] },
522
+ :storage => :s3,
523
+ :whiny_thumbnails => true,
524
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")),
525
+ :default_style => :medium,
526
+ :bucket => ENV['S3_TEST_BUCKET'],
527
+ :path => ":class/:attachment/:id/:style/:basename.:extension"
528
+ @dummy = Dummy.new
529
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
530
+ @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb')
531
+
532
+ assert @dummy.avatar = @file
533
+ assert @dummy.valid?
534
+ assert @dummy.save
535
+
536
+ @files_on_s3 = s3_files_for @dummy.avatar
537
+ end
538
+
539
+ context 'assigning itself to a new model' do
540
+ setup do
541
+ @d2 = Dummy.new
542
+ @d2.avatar = @dummy.avatar
543
+ @d2.save
544
+ end
545
+
546
+ should "have the same name as the old file" do
547
+ assert_equal @d2.avatar.original_filename, @dummy.avatar.original_filename
548
+ end
549
+ end
550
+
551
+ should "have the same contents as the original" do
552
+ @file.rewind
553
+ assert_equal @file.read, @files_on_s3[:original].read
554
+ end
555
+
556
+ should "write and delete its files" do
557
+ [["434x66", :original],
558
+ ["300x46", :large],
559
+ ["100x15", :medium],
560
+ ["32x32", :thumb]].each do |geo, style|
561
+ cmd = %Q[identify -format "%wx%h" "#{@files_on_s3[style].path}"]
562
+ assert_equal geo, `#{cmd}`.chomp, cmd
563
+ end
564
+
565
+ @d2 = Dummy.find(@dummy.id)
566
+ @d2_files = s3_files_for @d2.avatar
567
+ [["434x66", :original],
568
+ ["300x46", :large],
569
+ ["100x15", :medium],
570
+ ["32x32", :thumb]].each do |geo, style|
571
+ cmd = %Q[identify -format "%wx%h" "#{@d2_files[style].path}"]
572
+ assert_equal geo, `#{cmd}`.chomp, cmd
573
+ end
574
+
575
+ @dummy.avatar = "not a valid file but not nil"
576
+ assert_equal File.basename(@file.path), @dummy.avatar_file_name
577
+ assert @dummy.valid?
578
+ assert @dummy.save
579
+
580
+ [:thumb, :medium, :large, :original].each do |style|
581
+ assert @dummy.avatar.exists?(style)
582
+ end
583
+
584
+ @dummy.avatar.clear
585
+ assert_nil @dummy.avatar_file_name
586
+ assert @dummy.valid?
587
+ assert @dummy.save
588
+
589
+ [:thumb, :medium, :large, :original].each do |style|
590
+ assert ! @dummy.avatar.exists?(style)
591
+ end
592
+
593
+ @d2 = Dummy.find(@dummy.id)
594
+ assert_nil @d2.avatar_file_name
595
+ end
596
+
597
+ should "work exactly the same when new as when reloaded" do
598
+ @d2 = Dummy.find(@dummy.id)
599
+
600
+ assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
601
+ [:thumb, :medium, :large, :original].each do |style|
602
+ assert_equal @dummy.avatar.to_file(style).read, @d2.avatar.to_file(style).read
603
+ end
604
+
605
+ saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) }
606
+
607
+ @d2.avatar.clear
608
+ assert @d2.save
609
+
610
+ [:thumb, :medium, :large, :original].each do |style|
611
+ assert ! @dummy.avatar.exists?(style)
612
+ end
613
+ end
614
+
615
+ should "know the difference between good files, bad files, not files, and nil" do
616
+ expected = @dummy.avatar.to_file
617
+ @dummy.avatar = "not a file"
618
+ assert @dummy.valid?
619
+ assert_equal expected.read, @dummy.avatar.to_file.read
620
+
621
+ @dummy.avatar = @bad_file
622
+ assert ! @dummy.valid?
623
+ @dummy.avatar = nil
624
+ assert @dummy.valid?
625
+
626
+ Dummy.validates_attachment_presence :avatar
627
+ @d2 = Dummy.find(@dummy.id)
628
+ @d2.avatar = @file
629
+ assert @d2.valid?
630
+ @d2.avatar = @bad_file
631
+ assert ! @d2.valid?
632
+ @d2.avatar = nil
633
+ assert ! @d2.valid?
634
+ end
635
+
636
+ should "be able to reload without saving and not have the file disappear" do
637
+ @dummy.avatar = @file
638
+ assert @dummy.save
639
+ @dummy.avatar = nil
640
+ assert_nil @dummy.avatar_file_name
641
+ @dummy.reload
642
+ assert_equal "5k.png", @dummy.avatar_file_name
643
+ end
644
+
645
+ should "have the right content type" do
646
+ headers = s3_headers_for(@dummy.avatar, :original)
647
+ assert_equal 'image/png', headers['content-type']
648
+ end
649
+ end
650
+ end
651
+ end
652
+