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,71 @@
1
+ require 'test/helper'
2
+
3
+ class IOStreamTest < Test::Unit::TestCase
4
+ context "IOStream" do
5
+ should "be included in IO, File, Tempfile, and StringIO" do
6
+ [IO, File, Tempfile, StringIO].each do |klass|
7
+ assert klass.included_modules.include?(IOStream), "Not in #{klass}"
8
+ end
9
+ end
10
+ end
11
+
12
+ context "A file" do
13
+ setup do
14
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
15
+ end
16
+
17
+ teardown { @file.close }
18
+
19
+ context "that is sent #stream_to" do
20
+
21
+ context "and given a String" do
22
+ setup do
23
+ FileUtils.mkdir_p(File.join(ROOT, 'tmp'))
24
+ assert @result = @file.stream_to(File.join(ROOT, 'tmp', 'iostream.string.test'))
25
+ end
26
+
27
+ should "return a File" do
28
+ assert @result.is_a?(File)
29
+ end
30
+
31
+ should "contain the same data as the original file" do
32
+ @file.rewind; @result.rewind
33
+ assert_equal @file.read, @result.read
34
+ end
35
+ end
36
+
37
+ context "and given a Tempfile" do
38
+ setup do
39
+ tempfile = Tempfile.new('iostream.test')
40
+ tempfile.binmode
41
+ assert @result = @file.stream_to(tempfile)
42
+ end
43
+
44
+ should "return a Tempfile" do
45
+ assert @result.is_a?(Tempfile)
46
+ end
47
+
48
+ should "contain the same data as the original file" do
49
+ @file.rewind; @result.rewind
50
+ assert_equal @file.read, @result.read
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ context "that is sent #to_tempfile" do
57
+ setup do
58
+ assert @tempfile = @file.to_tempfile
59
+ end
60
+
61
+ should "convert it to a Tempfile" do
62
+ assert @tempfile.is_a?(Tempfile)
63
+ end
64
+
65
+ should "have the Tempfile contain the same data as the file" do
66
+ @file.rewind; @tempfile.rewind
67
+ assert_equal @file.read, @tempfile.read
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,21 @@
1
+ require 'test/helper'
2
+
3
+ class HaveAttachedFileMatcherTest < Test::Unit::TestCase
4
+ context "have_attached_file" do
5
+ setup do
6
+ @dummy_class = reset_class "Dummy"
7
+ reset_table "dummies"
8
+ @matcher = self.class.have_attached_file(:avatar)
9
+ end
10
+
11
+ should "reject a class with no attachment" do
12
+ assert_rejects @matcher, @dummy_class
13
+ end
14
+
15
+ should "accept a class with an attachment" do
16
+ modify_table("dummies"){|d| d.string :avatar_file_name }
17
+ @dummy_class.has_attached_file :avatar
18
+ assert_accepts @matcher, @dummy_class
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ require 'test/helper'
2
+
3
+ class ValidateAttachmentContentTypeMatcherTest < Test::Unit::TestCase
4
+ context "validate_attachment_content_type" do
5
+ setup do
6
+ reset_table("dummies") do |d|
7
+ d.string :avatar_file_name
8
+ end
9
+ @dummy_class = reset_class "Dummy"
10
+ @dummy_class.has_attached_file :avatar
11
+ @matcher = self.class.validate_attachment_content_type(:avatar).
12
+ allowing(%w(image/png image/jpeg)).
13
+ rejecting(%w(audio/mp3 application/octet-stream))
14
+ end
15
+
16
+ should "reject a class with no validation" do
17
+ assert_rejects @matcher, @dummy_class
18
+ end
19
+
20
+ should "reject a class with a validation that doesn't match" do
21
+ @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{audio/.*}
22
+ assert_rejects @matcher, @dummy_class
23
+ end
24
+
25
+ should "accept a class with a validation" do
26
+ @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
27
+ assert_accepts @matcher, @dummy_class
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ require 'test/helper'
2
+
3
+ class ValidateAttachmentPresenceMatcherTest < Test::Unit::TestCase
4
+ context "validate_attachment_presence" do
5
+ setup do
6
+ reset_table("dummies"){|d| d.string :avatar_file_name }
7
+ @dummy_class = reset_class "Dummy"
8
+ @dummy_class.has_attached_file :avatar
9
+ @matcher = self.class.validate_attachment_presence(:avatar)
10
+ end
11
+
12
+ should "reject a class with no validation" do
13
+ assert_rejects @matcher, @dummy_class
14
+ end
15
+
16
+ should "accept a class with a validation" do
17
+ @dummy_class.validates_attachment_presence :avatar
18
+ assert_accepts @matcher, @dummy_class
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,50 @@
1
+ require 'test/helper'
2
+
3
+ class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase
4
+ context "validate_attachment_size" do
5
+ setup do
6
+ reset_table("dummies") do |d|
7
+ d.string :avatar_file_name
8
+ end
9
+ @dummy_class = reset_class "Dummy"
10
+ @dummy_class.has_attached_file :avatar
11
+ end
12
+
13
+ context "of limited size" do
14
+ setup{ @matcher = self.class.validate_attachment_size(:avatar).in(256..1024) }
15
+
16
+ should "reject a class with no validation" do
17
+ assert_rejects @matcher, @dummy_class
18
+ end
19
+
20
+ should "reject a class with a validation that's too high" do
21
+ @dummy_class.validates_attachment_size :avatar, :in => 256..2048
22
+ assert_rejects @matcher, @dummy_class
23
+ end
24
+
25
+ should "reject a class with a validation that's too low" do
26
+ @dummy_class.validates_attachment_size :avatar, :in => 0..1024
27
+ assert_rejects @matcher, @dummy_class
28
+ end
29
+
30
+ should "accept a class with a validation that matches" do
31
+ @dummy_class.validates_attachment_size :avatar, :in => 256..1024
32
+ assert_accepts @matcher, @dummy_class
33
+ end
34
+ end
35
+
36
+ context "validates_attachment_size with infinite range" do
37
+ setup{ @matcher = self.class.validate_attachment_size(:avatar) }
38
+
39
+ should "accept a class with an upper limit" do
40
+ @dummy_class.validates_attachment_size :avatar, :less_than => 1
41
+ assert_accepts @matcher, @dummy_class
42
+ end
43
+
44
+ should "accept a class with no upper limit" do
45
+ @dummy_class.validates_attachment_size :avatar, :greater_than => 1
46
+ assert_accepts @matcher, @dummy_class
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,233 @@
1
+ require 'test/helper'
2
+
3
+ class PaperclipTest < Test::Unit::TestCase
4
+ [:image_magick_path, :convert_path].each do |path|
5
+ context "Calling Paperclip.run with an #{path} specified" do
6
+ setup do
7
+ Paperclip.options[:image_magick_path] = nil
8
+ Paperclip.options[:convert_path] = nil
9
+ Paperclip.options[path] = "/usr/bin"
10
+ end
11
+
12
+ should "execute the right command" do
13
+ Paperclip.expects(:path_for_command).with("convert").returns("/usr/bin/convert")
14
+ Paperclip.expects(:bit_bucket).returns("/dev/null")
15
+ Paperclip.expects(:"`").with("/usr/bin/convert one.jpg two.jpg 2>/dev/null")
16
+ Paperclip.run("convert", "one.jpg two.jpg")
17
+ end
18
+ end
19
+ end
20
+
21
+ context "Calling Paperclip.run with no path specified" do
22
+ setup do
23
+ Paperclip.options[:image_magick_path] = nil
24
+ Paperclip.options[:convert_path] = nil
25
+ end
26
+
27
+ should "execute the right command" do
28
+ Paperclip.expects(:path_for_command).with("convert").returns("convert")
29
+ Paperclip.expects(:bit_bucket).returns("/dev/null")
30
+ Paperclip.expects(:"`").with("convert one.jpg two.jpg 2>/dev/null")
31
+ Paperclip.run("convert", "one.jpg two.jpg")
32
+ end
33
+ end
34
+
35
+ should "raise when sent #processor and the name of a class that exists but isn't a subclass of Processor" do
36
+ assert_raises(Paperclip::PaperclipError){ Paperclip.processor(:attachment) }
37
+ end
38
+
39
+ should "raise when sent #processor and the name of a class that doesn't exist" do
40
+ assert_raises(NameError){ Paperclip.processor(:boogey_man) }
41
+ end
42
+
43
+ should "return a class when sent #processor and the name of a class under Paperclip" do
44
+ assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail)
45
+ end
46
+
47
+ context "Paperclip.bit_bucket" do
48
+ context "on systems without /dev/null" do
49
+ setup do
50
+ File.expects(:exists?).with("/dev/null").returns(false)
51
+ end
52
+
53
+ should "return 'NUL'" do
54
+ assert_equal "NUL", Paperclip.bit_bucket
55
+ end
56
+ end
57
+
58
+ context "on systems with /dev/null" do
59
+ setup do
60
+ File.expects(:exists?).with("/dev/null").returns(true)
61
+ end
62
+
63
+ should "return '/dev/null'" do
64
+ assert_equal "/dev/null", Paperclip.bit_bucket
65
+ end
66
+ end
67
+ end
68
+
69
+ context "An ActiveRecord model with an 'avatar' attachment" do
70
+ setup do
71
+ rebuild_model :path => "tmp/:class/omg/:style.:extension"
72
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
73
+ end
74
+
75
+ teardown { @file.close }
76
+
77
+ should "not error when trying to also create a 'blah' attachment" do
78
+ assert_nothing_raised do
79
+ Dummy.class_eval do
80
+ has_attached_file :blah
81
+ end
82
+ end
83
+ end
84
+
85
+ context "that is attr_protected" do
86
+ setup do
87
+ Dummy.class_eval do
88
+ attr_protected :avatar
89
+ end
90
+ @dummy = Dummy.new
91
+ end
92
+
93
+ should "not assign the avatar on mass-set" do
94
+ @dummy.attributes = { :other => "I'm set!",
95
+ :avatar => @file }
96
+
97
+ assert_equal "I'm set!", @dummy.other
98
+ assert ! @dummy.avatar?
99
+ end
100
+
101
+ should "still allow assigment on normal set" do
102
+ @dummy.other = "I'm set!"
103
+ @dummy.avatar = @file
104
+
105
+ assert_equal "I'm set!", @dummy.other
106
+ assert @dummy.avatar?
107
+ end
108
+ end
109
+
110
+ context "with a subclass" do
111
+ setup do
112
+ class ::SubDummy < Dummy; end
113
+ end
114
+
115
+ should "be able to use the attachment from the subclass" do
116
+ assert_nothing_raised do
117
+ @subdummy = SubDummy.create(:avatar => @file)
118
+ end
119
+ end
120
+
121
+ should "be able to see the attachment definition from the subclass's class" do
122
+ assert_equal "tmp/:class/omg/:style.:extension", SubDummy.attachment_definitions[:avatar][:path]
123
+ end
124
+
125
+ teardown do
126
+ Object.send(:remove_const, "SubDummy") rescue nil
127
+ end
128
+ end
129
+
130
+ should "have an #avatar method" do
131
+ assert Dummy.new.respond_to?(:avatar)
132
+ end
133
+
134
+ should "have an #avatar= method" do
135
+ assert Dummy.new.respond_to?(:avatar=)
136
+ end
137
+
138
+ context "that is valid" do
139
+ setup do
140
+ @dummy = Dummy.new
141
+ @dummy.avatar = @file
142
+ end
143
+
144
+ should "be valid" do
145
+ assert @dummy.valid?
146
+ end
147
+
148
+ context "then has a validation added that makes it invalid" do
149
+ setup do
150
+ assert @dummy.save
151
+ Dummy.class_eval do
152
+ validates_attachment_content_type :avatar, :content_type => ["text/plain"]
153
+ end
154
+ @dummy2 = Dummy.find(@dummy.id)
155
+ end
156
+
157
+ should "be invalid when reloaded" do
158
+ assert ! @dummy2.valid?, @dummy2.errors.inspect
159
+ end
160
+
161
+ should "be able to call #valid? twice without having duplicate errors" do
162
+ @dummy2.avatar.valid?
163
+ first_errors = @dummy2.avatar.errors
164
+ @dummy2.avatar.valid?
165
+ assert_equal first_errors, @dummy2.avatar.errors
166
+ end
167
+ end
168
+ end
169
+
170
+ def self.should_validate validation, options, valid_file, invalid_file
171
+ context "with #{validation} validation and #{options.inspect} options" do
172
+ setup do
173
+ Dummy.send(:"validates_attachment_#{validation}", :avatar, options)
174
+ @dummy = Dummy.new
175
+ end
176
+ context "and assigning nil" do
177
+ setup do
178
+ @dummy.avatar = nil
179
+ @dummy.valid?
180
+ end
181
+ if validation == :presence
182
+ should "have an error on the attachment" do
183
+ assert @dummy.errors.on(:avatar)
184
+ end
185
+ else
186
+ should "not have an error on the attachment" do
187
+ assert_nil @dummy.errors.on(:avatar)
188
+ end
189
+ end
190
+ end
191
+ context "and assigned a valid file" do
192
+ setup do
193
+ @dummy.avatar = valid_file
194
+ @dummy.valid?
195
+ end
196
+ should "not have an error when assigned a valid file" do
197
+ assert ! @dummy.avatar.errors.key?(validation)
198
+ end
199
+ should "not have an error on the attachment" do
200
+ assert_nil @dummy.errors.on(:avatar)
201
+ end
202
+ end
203
+ context "and assigned an invalid file" do
204
+ setup do
205
+ @dummy.avatar = invalid_file
206
+ @dummy.valid?
207
+ end
208
+ should "have an error when assigned a valid file" do
209
+ assert_not_nil @dummy.avatar.errors[validation]
210
+ end
211
+ should "have an error on the attachment" do
212
+ assert @dummy.errors.on(:avatar)
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ [[:presence, {}, "5k.png", nil],
219
+ [:size, {:in => 1..10240}, nil, "12k.png"],
220
+ [:size, {:less_than => 10240}, "5k.png", "12k.png"],
221
+ [:size, {:greater_than => 8096}, "12k.png", "5k.png"],
222
+ [:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"],
223
+ [:content_type, {:content_type => "text/plain"}, "text.txt", "5k.png"],
224
+ [:content_type, {:content_type => %r{image/.*}}, "5k.png", "text.txt"]].each do |args|
225
+ validation, options, valid_file, invalid_file = args
226
+ valid_file &&= File.open(File.join(FIXTURES_DIR, valid_file), "rb")
227
+ invalid_file &&= File.open(File.join(FIXTURES_DIR, invalid_file), "rb")
228
+
229
+ should_validate validation, options, valid_file, invalid_file
230
+ end
231
+
232
+ end
233
+ end
@@ -0,0 +1,10 @@
1
+ require 'test/helper'
2
+
3
+ class ProcessorTest < Test::Unit::TestCase
4
+ should "instantiate and call #make when sent #make to the class" do
5
+ processor = mock
6
+ processor.expects(:make).with()
7
+ Paperclip::Processor.expects(:new).with(:one, :two, :three).returns(processor)
8
+ Paperclip::Processor.make(:one, :two, :three)
9
+ end
10
+ end
@@ -0,0 +1,277 @@
1
+ require 'test/helper'
2
+
3
+ class StorageTest < Test::Unit::TestCase
4
+ context "Parsing S3 credentials" do
5
+ setup do
6
+ rebuild_model :storage => :s3,
7
+ :bucket => "testing",
8
+ :s3_credentials => {:not => :important}
9
+
10
+ @dummy = Dummy.new
11
+ @avatar = @dummy.avatar
12
+
13
+ @current_env = ENV['RAILS_ENV']
14
+ end
15
+
16
+ teardown do
17
+ ENV['RAILS_ENV'] = @current_env
18
+ end
19
+
20
+ should "get the correct credentials when RAILS_ENV is production" do
21
+ ENV['RAILS_ENV'] = 'production'
22
+ assert_equal({:key => "12345"},
23
+ @avatar.parse_credentials('production' => {:key => '12345'},
24
+ :development => {:key => "54321"}))
25
+ end
26
+
27
+ should "get the correct credentials when RAILS_ENV is development" do
28
+ ENV['RAILS_ENV'] = 'development'
29
+ assert_equal({:key => "54321"},
30
+ @avatar.parse_credentials('production' => {:key => '12345'},
31
+ :development => {:key => "54321"}))
32
+ end
33
+
34
+ should "return the argument if the key does not exist" do
35
+ ENV['RAILS_ENV'] = "not really an env"
36
+ assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345"))
37
+ end
38
+ end
39
+
40
+ context "" do
41
+ setup do
42
+ rebuild_model :storage => :s3,
43
+ :s3_credentials => {},
44
+ :bucket => "bucket",
45
+ :path => ":attachment/:basename.:extension",
46
+ :url => ":s3_path_url"
47
+ @dummy = Dummy.new
48
+ @dummy.avatar = StringIO.new(".")
49
+ end
50
+
51
+ should "return a url based on an S3 path" do
52
+ assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
53
+ end
54
+ end
55
+ context "" do
56
+ setup do
57
+ rebuild_model :storage => :s3,
58
+ :s3_credentials => {},
59
+ :bucket => "bucket",
60
+ :path => ":attachment/:basename.:extension",
61
+ :url => ":s3_domain_url"
62
+ @dummy = Dummy.new
63
+ @dummy.avatar = StringIO.new(".")
64
+ end
65
+
66
+ should "return a url based on an S3 subdomain" do
67
+ assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url
68
+ end
69
+ end
70
+ context "" do
71
+ setup do
72
+ rebuild_model :storage => :s3,
73
+ :s3_credentials => {
74
+ :production => { :bucket => "prod_bucket" },
75
+ :development => { :bucket => "dev_bucket" }
76
+ },
77
+ :s3_host_alias => "something.something.com",
78
+ :path => ":attachment/:basename.:extension",
79
+ :url => ":s3_alias_url"
80
+ @dummy = Dummy.new
81
+ @dummy.avatar = StringIO.new(".")
82
+ end
83
+
84
+ should "return a url based on the host_alias" do
85
+ assert_match %r{^http://something.something.com/avatars/stringio.txt}, @dummy.avatar.url
86
+ end
87
+ end
88
+
89
+ context "Parsing S3 credentials with a bucket in them" do
90
+ setup do
91
+ rebuild_model :storage => :s3,
92
+ :s3_credentials => {
93
+ :production => { :bucket => "prod_bucket" },
94
+ :development => { :bucket => "dev_bucket" }
95
+ }
96
+ @dummy = Dummy.new
97
+ end
98
+
99
+ should "get the right bucket in production", :before => lambda{ ENV.expects(:[]).returns('production') } do
100
+ assert_equal "prod_bucket", @dummy.avatar.bucket_name
101
+ end
102
+
103
+ should "get the right bucket in development", :before => lambda{ ENV.expects(:[]).returns('development') } do
104
+ assert_equal "dev_bucket", @dummy.avatar.bucket_name
105
+ end
106
+ end
107
+
108
+ context "An attachment with S3 storage" do
109
+ setup do
110
+ rebuild_model :storage => :s3,
111
+ :bucket => "testing",
112
+ :path => ":attachment/:style/:basename.:extension",
113
+ :s3_credentials => {
114
+ 'access_key_id' => "12345",
115
+ 'secret_access_key' => "54321"
116
+ }
117
+ end
118
+
119
+ should "be extended by the S3 module" do
120
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
121
+ end
122
+
123
+ should "not be extended by the Filesystem module" do
124
+ assert ! Dummy.new.avatar.is_a?(Paperclip::Storage::Filesystem)
125
+ end
126
+
127
+ context "when assigned" do
128
+ setup do
129
+ @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
130
+ @dummy = Dummy.new
131
+ @dummy.avatar = @file
132
+ end
133
+
134
+ teardown { @file.close }
135
+
136
+ should "not get a bucket to get a URL" do
137
+ @dummy.avatar.expects(:s3).never
138
+ @dummy.avatar.expects(:s3_bucket).never
139
+ assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url
140
+ end
141
+
142
+ context "and saved" do
143
+ setup do
144
+ @s3_mock = stub
145
+ @bucket_mock = stub
146
+ RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock)
147
+ @s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock)
148
+ @key_mock = stub
149
+ @bucket_mock.expects(:key).returns(@key_mock)
150
+ @key_mock.expects(:data=)
151
+ @key_mock.expects(:put).with(nil, 'public-read', 'Content-type' => 'image/png')
152
+ @dummy.save
153
+ end
154
+
155
+ should "succeed" do
156
+ assert true
157
+ end
158
+ end
159
+
160
+ context "and remove" do
161
+ setup do
162
+ @s3_mock = stub
163
+ @bucket_mock = stub
164
+ RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock)
165
+ @s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock)
166
+ @key_mock = stub
167
+ @bucket_mock.expects(:key).at_least(2).returns(@key_mock)
168
+ @key_mock.expects(:delete)
169
+ @dummy.destroy_attached_files
170
+ end
171
+
172
+ should "succeed" do
173
+ assert true
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ context "An attachment with S3 storage and bucket defined as a Proc" do
180
+ setup do
181
+ rebuild_model :storage => :s3,
182
+ :bucket => lambda { |attachment| "bucket_#{attachment.instance.other}" },
183
+ :s3_credentials => {:not => :important}
184
+ end
185
+
186
+ should "get the right bucket name" do
187
+ assert "bucket_a", Dummy.new(:other => 'a').avatar.bucket_name
188
+ assert "bucket_b", Dummy.new(:other => 'b').avatar.bucket_name
189
+ end
190
+ end
191
+
192
+ context "An attachment with S3 storage and specific s3 headers set" do
193
+ setup do
194
+ rebuild_model :storage => :s3,
195
+ :bucket => "testing",
196
+ :path => ":attachment/:style/:basename.:extension",
197
+ :s3_credentials => {
198
+ 'access_key_id' => "12345",
199
+ 'secret_access_key' => "54321"
200
+ },
201
+ :s3_headers => {'Cache-Control' => 'max-age=31557600'}
202
+ end
203
+
204
+ context "when assigned" do
205
+ setup do
206
+ @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
207
+ @dummy = Dummy.new
208
+ @dummy.avatar = @file
209
+ end
210
+
211
+ teardown { @file.close }
212
+
213
+ context "and saved" do
214
+ setup do
215
+ @s3_mock = stub
216
+ @bucket_mock = stub
217
+ RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock)
218
+ @s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock)
219
+ @key_mock = stub
220
+ @bucket_mock.expects(:key).returns(@key_mock)
221
+ @key_mock.expects(:data=)
222
+ @key_mock.expects(:put).with(nil,
223
+ 'public-read',
224
+ 'Content-type' => 'image/png',
225
+ 'Cache-Control' => 'max-age=31557600')
226
+ @dummy.save
227
+ end
228
+
229
+ should "succeed" do
230
+ assert true
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ unless ENV["S3_TEST_BUCKET"].blank?
237
+ context "Using S3 for real, an attachment with S3 storage" do
238
+ setup do
239
+ rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" },
240
+ :storage => :s3,
241
+ :bucket => ENV["S3_TEST_BUCKET"],
242
+ :path => ":class/:attachment/:id/:style.:extension",
243
+ :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml"))
244
+
245
+ Dummy.delete_all
246
+ @dummy = Dummy.new
247
+ end
248
+
249
+ should "be extended by the S3 module" do
250
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
251
+ end
252
+
253
+ context "when assigned" do
254
+ setup do
255
+ @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
256
+ @dummy.avatar = @file
257
+ end
258
+
259
+ teardown { @file.close }
260
+
261
+ should "still return a Tempfile when sent #to_io" do
262
+ assert_equal Tempfile, @dummy.avatar.to_io.class
263
+ end
264
+
265
+ context "and saved" do
266
+ setup do
267
+ @dummy.save
268
+ end
269
+
270
+ should "be on S3" do
271
+ assert true
272
+ end
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end