paperclip-cloudfiles 2.3.1.1.0

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/LICENSE +26 -0
  2. data/README.rdoc +176 -0
  3. data/Rakefile +105 -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 +356 -0
  9. data/lib/paperclip/attachment.rb +414 -0
  10. data/lib/paperclip/callback_compatability.rb +33 -0
  11. data/lib/paperclip/geometry.rb +115 -0
  12. data/lib/paperclip/interpolations.rb +108 -0
  13. data/lib/paperclip/iostream.rb +59 -0
  14. data/lib/paperclip/matchers.rb +4 -0
  15. data/lib/paperclip/matchers/have_attached_file_matcher.rb +49 -0
  16. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +65 -0
  17. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +48 -0
  18. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +85 -0
  19. data/lib/paperclip/processor.rb +49 -0
  20. data/lib/paperclip/storage.rb +369 -0
  21. data/lib/paperclip/thumbnail.rb +73 -0
  22. data/lib/paperclip/upfile.rb +49 -0
  23. data/shoulda_macros/paperclip.rb +117 -0
  24. data/tasks/paperclip_tasks.rake +79 -0
  25. data/test/attachment_test.rb +780 -0
  26. data/test/cloudfiles.yml +13 -0
  27. data/test/database.yml +4 -0
  28. data/test/fixtures/12k.png +0 -0
  29. data/test/fixtures/50x50.png +0 -0
  30. data/test/fixtures/5k.png +0 -0
  31. data/test/fixtures/bad.png +1 -0
  32. data/test/fixtures/s3.yml +8 -0
  33. data/test/fixtures/text.txt +0 -0
  34. data/test/fixtures/twopage.pdf +0 -0
  35. data/test/geometry_test.rb +177 -0
  36. data/test/helper.rb +111 -0
  37. data/test/integration_test.rb +483 -0
  38. data/test/interpolations_test.rb +124 -0
  39. data/test/iostream_test.rb +78 -0
  40. data/test/matchers/have_attached_file_matcher_test.rb +21 -0
  41. data/test/matchers/validate_attachment_content_type_matcher_test.rb +31 -0
  42. data/test/matchers/validate_attachment_presence_matcher_test.rb +23 -0
  43. data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
  44. data/test/paperclip_test.rb +319 -0
  45. data/test/processor_test.rb +10 -0
  46. data/test/storage_test.rb +549 -0
  47. data/test/thumbnail_test.rb +227 -0
  48. data/test/upfile_test.rb +28 -0
  49. metadata +175 -0
@@ -0,0 +1,124 @@
1
+ require 'test/helper'
2
+
3
+ class InterpolationsTest < Test::Unit::TestCase
4
+ should "return all methods but the infrastructure when sent #all" do
5
+ methods = Paperclip::Interpolations.all
6
+ assert ! methods.include?(:[])
7
+ assert ! methods.include?(:[]=)
8
+ assert ! methods.include?(:all)
9
+ methods.each do |m|
10
+ assert Paperclip::Interpolations.respond_to?(m)
11
+ end
12
+ end
13
+
14
+ should "return the RAILS_ROOT" do
15
+ assert_equal RAILS_ROOT, Paperclip::Interpolations.rails_root(:attachment, :style)
16
+ end
17
+
18
+ should "return the RAILS_ENV" do
19
+ assert_equal RAILS_ENV, Paperclip::Interpolations.rails_env(:attachment, :style)
20
+ end
21
+
22
+ should "return the class of the Interpolations module when called with no params" do
23
+ assert_equal Module, Paperclip::Interpolations.class
24
+ end
25
+
26
+ should "return the class of the instance" do
27
+ attachment = mock
28
+ attachment.expects(:instance).returns(attachment)
29
+ attachment.expects(:class).returns("Thing")
30
+ assert_equal "things", Paperclip::Interpolations.class(attachment, :style)
31
+ end
32
+
33
+ should "return the basename of the file" do
34
+ attachment = mock
35
+ attachment.expects(:original_filename).returns("one.jpg").times(2)
36
+ assert_equal "one", Paperclip::Interpolations.basename(attachment, :style)
37
+ end
38
+
39
+ should "return the extension of the file" do
40
+ attachment = mock
41
+ attachment.expects(:original_filename).returns("one.jpg")
42
+ attachment.expects(:styles).returns({})
43
+ assert_equal "jpg", Paperclip::Interpolations.extension(attachment, :style)
44
+ end
45
+
46
+ should "return the extension of the file as the format if defined in the style" do
47
+ attachment = mock
48
+ attachment.expects(:original_filename).never
49
+ attachment.expects(:styles).returns({:style => {:format => "png"}})
50
+ assert_equal "png", Paperclip::Interpolations.extension(attachment, :style)
51
+ end
52
+
53
+ should "return the id of the attachment" do
54
+ attachment = mock
55
+ attachment.expects(:id).returns(23)
56
+ attachment.expects(:instance).returns(attachment)
57
+ assert_equal 23, Paperclip::Interpolations.id(attachment, :style)
58
+ end
59
+
60
+ should "return the partitioned id of the attachment" do
61
+ attachment = mock
62
+ attachment.expects(:id).returns(23)
63
+ attachment.expects(:instance).returns(attachment)
64
+ assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style)
65
+ end
66
+
67
+ should "return the name of the attachment" do
68
+ attachment = mock
69
+ attachment.expects(:name).returns("file")
70
+ assert_equal "files", Paperclip::Interpolations.attachment(attachment, :style)
71
+ end
72
+
73
+ should "return the style" do
74
+ assert_equal :style, Paperclip::Interpolations.style(:attachment, :style)
75
+ end
76
+
77
+ should "return the default style" do
78
+ attachment = mock
79
+ attachment.expects(:default_style).returns(:default_style)
80
+ assert_equal :default_style, Paperclip::Interpolations.style(attachment, nil)
81
+ end
82
+
83
+ should "reinterpolate :url" do
84
+ attachment = mock
85
+ attachment.expects(:options).returns({:url => ":id"})
86
+ attachment.expects(:url).with(:style, false).returns("1234")
87
+ assert_equal "1234", Paperclip::Interpolations.url(attachment, :style)
88
+ end
89
+
90
+ should "raise if infinite loop detcted reinterpolating :url" do
91
+ attachment = mock
92
+ attachment.expects(:options).returns({:url => ":url"})
93
+ assert_raises(Paperclip::InfiniteInterpolationError){ Paperclip::Interpolations.url(attachment, :style) }
94
+ end
95
+
96
+ should "return the filename as basename.extension" do
97
+ attachment = mock
98
+ attachment.expects(:styles).returns({})
99
+ attachment.expects(:original_filename).returns("one.jpg").times(3)
100
+ assert_equal "one.jpg", Paperclip::Interpolations.filename(attachment, :style)
101
+ end
102
+
103
+ should "return the filename as basename.extension when format supplied" do
104
+ attachment = mock
105
+ attachment.expects(:styles).returns({:style => {:format => :png}})
106
+ attachment.expects(:original_filename).returns("one.jpg").times(2)
107
+ assert_equal "one.png", Paperclip::Interpolations.filename(attachment, :style)
108
+ end
109
+
110
+ should "return the timestamp" do
111
+ now = Time.now
112
+ attachment = mock
113
+ attachment.expects(:instance_read).with(:updated_at).returns(now)
114
+ assert_equal now.to_s, Paperclip::Interpolations.timestamp(attachment, :style)
115
+ end
116
+
117
+ should "call all expected interpolations with the given arguments" do
118
+ Paperclip::Interpolations.expects(:id).with(:attachment, :style).returns(1234)
119
+ Paperclip::Interpolations.expects(:attachment).with(:attachment, :style).returns("attachments")
120
+ Paperclip::Interpolations.expects(:notreal).never
121
+ value = Paperclip::Interpolations.interpolate(":notreal/:id/:attachment", :attachment, :style)
122
+ assert_equal ":notreal/1234/attachments", value
123
+ end
124
+ end
@@ -0,0 +1,78 @@
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 Paperclip Tempfile" do
62
+ assert @tempfile.is_a?(Paperclip::Tempfile)
63
+ end
64
+
65
+ should "have the name be based on the original_filename" do
66
+ name = File.basename(@file.path)
67
+ extension = File.extname(name)
68
+ basename = File.basename(name, extension)
69
+ assert_match %r[^#{Regexp.quote(basename)}.*?#{Regexp.quote(extension)}], File.basename(@tempfile.path)
70
+ end
71
+
72
+ should "have the Tempfile contain the same data as the file" do
73
+ @file.rewind; @tempfile.rewind
74
+ assert_equal @file.read, @tempfile.read
75
+ end
76
+ end
77
+ end
78
+ 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,31 @@
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
+ d.string :avatar_content_type
9
+ end
10
+ @dummy_class = reset_class "Dummy"
11
+ @dummy_class.has_attached_file :avatar
12
+ @matcher = self.class.validate_attachment_content_type(:avatar).
13
+ allowing(%w(image/png image/jpeg)).
14
+ rejecting(%w(audio/mp3 application/octet-stream))
15
+ end
16
+
17
+ should "reject a class with no validation" do
18
+ assert_rejects @matcher, @dummy_class
19
+ end
20
+
21
+ should "reject a class with a validation that doesn't match" do
22
+ @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{audio/.*}
23
+ assert_rejects @matcher, @dummy_class
24
+ end
25
+
26
+ should "accept a class with a validation" do
27
+ @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
28
+ assert_accepts @matcher, @dummy_class
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ require 'test/helper'
2
+
3
+ class ValidateAttachmentPresenceMatcherTest < Test::Unit::TestCase
4
+ context "validate_attachment_presence" 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_presence(:avatar)
12
+ end
13
+
14
+ should "reject a class with no validation" do
15
+ assert_rejects @matcher, @dummy_class
16
+ end
17
+
18
+ should "accept a class with a validation" do
19
+ @dummy_class.validates_attachment_presence :avatar
20
+ assert_accepts @matcher, @dummy_class
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,51 @@
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
+ d.integer :avatar_file_size
9
+ end
10
+ @dummy_class = reset_class "Dummy"
11
+ @dummy_class.has_attached_file :avatar
12
+ end
13
+
14
+ context "of limited size" do
15
+ setup{ @matcher = self.class.validate_attachment_size(:avatar).in(256..1024) }
16
+
17
+ should "reject a class with no validation" do
18
+ assert_rejects @matcher, @dummy_class
19
+ end
20
+
21
+ should "reject a class with a validation that's too high" do
22
+ @dummy_class.validates_attachment_size :avatar, :in => 256..2048
23
+ assert_rejects @matcher, @dummy_class
24
+ end
25
+
26
+ should "reject a class with a validation that's too low" do
27
+ @dummy_class.validates_attachment_size :avatar, :in => 0..1024
28
+ assert_rejects @matcher, @dummy_class
29
+ end
30
+
31
+ should "accept a class with a validation that matches" do
32
+ @dummy_class.validates_attachment_size :avatar, :in => 256..1024
33
+ assert_accepts @matcher, @dummy_class
34
+ end
35
+ end
36
+
37
+ context "validates_attachment_size with infinite range" do
38
+ setup{ @matcher = self.class.validate_attachment_size(:avatar) }
39
+
40
+ should "accept a class with an upper limit" do
41
+ @dummy_class.validates_attachment_size :avatar, :less_than => 1
42
+ assert_accepts @matcher, @dummy_class
43
+ end
44
+
45
+ should "accept a class with no upper limit" do
46
+ @dummy_class.validates_attachment_size :avatar, :greater_than => 1
47
+ assert_accepts @matcher, @dummy_class
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,319 @@
1
+ require 'test/helper'
2
+
3
+ class PaperclipTest < Test::Unit::TestCase
4
+ [:image_magick_path, :command_path].each do |path|
5
+ context "Calling Paperclip.run with #{path} specified" do
6
+ setup do
7
+ Paperclip.options[:image_magick_path] = nil
8
+ Paperclip.options[:command_path] = nil
9
+ Paperclip.options[path] = "/usr/bin"
10
+ end
11
+
12
+ should "return the expected path for path_for_command" do
13
+ assert_equal "/usr/bin/convert", Paperclip.path_for_command("convert")
14
+ end
15
+
16
+ should "execute the right command" do
17
+ Paperclip.expects(:path_for_command).with("convert").returns("/usr/bin/convert")
18
+ Paperclip.expects(:bit_bucket).returns("/dev/null")
19
+ Paperclip.expects(:"`").with("/usr/bin/convert one.jpg two.jpg 2>/dev/null")
20
+ Paperclip.run("convert", "one.jpg two.jpg")
21
+ end
22
+ end
23
+ end
24
+
25
+ context "Calling Paperclip.run with no path specified" do
26
+ setup do
27
+ Paperclip.options[:image_magick_path] = nil
28
+ Paperclip.options[:command_path] = nil
29
+ end
30
+
31
+ should "return the expected path fro path_for_command" do
32
+ assert_equal "convert", Paperclip.path_for_command("convert")
33
+ end
34
+
35
+ should "execute the right command" do
36
+ Paperclip.expects(:path_for_command).with("convert").returns("convert")
37
+ Paperclip.expects(:bit_bucket).returns("/dev/null")
38
+ Paperclip.expects(:"`").with("convert one.jpg two.jpg 2>/dev/null")
39
+ Paperclip.run("convert", "one.jpg two.jpg")
40
+ end
41
+ end
42
+
43
+ context "Calling Paperclip.run and logging" do
44
+ setup do
45
+ Paperclip.options[:image_magick_path] = nil
46
+ Paperclip.options[:command_path] = nil
47
+ Paperclip.stubs(:bit_bucket).returns("/dev/null")
48
+ Paperclip.stubs(:log)
49
+ Paperclip.stubs(:"`").with("this is the command 2>/dev/null")
50
+ end
51
+
52
+ should "log the command when :log_command is true" do
53
+ Paperclip.options[:log_command] = true
54
+ Paperclip.run("this","is the command")
55
+ assert_received(Paperclip, :log) do |p|
56
+ p.with("this is the command 2>/dev/null")
57
+ end
58
+ assert_received(Paperclip, :`) do |p|
59
+ p.with("this is the command 2>/dev/null")
60
+ end
61
+ end
62
+
63
+ should "not log the command when :log_command is false" do
64
+ Paperclip.options[:log_command] = false
65
+ Paperclip.run("this","is the command")
66
+ assert_received(Paperclip, :log) do |p|
67
+ p.with("this is the command 2>/dev/null").never
68
+ end
69
+ assert_received(Paperclip, :`) do |p|
70
+ p.with("this is the command 2>/dev/null")
71
+ end
72
+ end
73
+ end
74
+
75
+ context "Paperclip.bit_bucket" do
76
+ context "on systems without /dev/null" do
77
+ setup do
78
+ File.expects(:exists?).with("/dev/null").returns(false)
79
+ end
80
+
81
+ should "return 'NUL'" do
82
+ assert_equal "NUL", Paperclip.bit_bucket
83
+ end
84
+ end
85
+
86
+ context "on systems with /dev/null" do
87
+ setup do
88
+ File.expects(:exists?).with("/dev/null").returns(true)
89
+ end
90
+
91
+ should "return '/dev/null'" do
92
+ assert_equal "/dev/null", Paperclip.bit_bucket
93
+ end
94
+ end
95
+ end
96
+
97
+ should "raise when sent #processor and the name of a class that exists but isn't a subclass of Processor" do
98
+ assert_raises(Paperclip::PaperclipError){ Paperclip.processor(:attachment) }
99
+ end
100
+
101
+ should "raise when sent #processor and the name of a class that doesn't exist" do
102
+ assert_raises(NameError){ Paperclip.processor(:boogey_man) }
103
+ end
104
+
105
+ should "return a class when sent #processor and the name of a class under Paperclip" do
106
+ assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail)
107
+ end
108
+
109
+ context "An ActiveRecord model with an 'avatar' attachment" do
110
+ setup do
111
+ rebuild_model :path => "tmp/:class/omg/:style.:extension"
112
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
113
+ end
114
+
115
+ teardown { @file.close }
116
+
117
+ should "not error when trying to also create a 'blah' attachment" do
118
+ assert_nothing_raised do
119
+ Dummy.class_eval do
120
+ has_attached_file :blah
121
+ end
122
+ end
123
+ end
124
+
125
+ context "that is attr_protected" do
126
+ setup do
127
+ Dummy.class_eval do
128
+ attr_protected :avatar
129
+ end
130
+ @dummy = Dummy.new
131
+ end
132
+
133
+ should "not assign the avatar on mass-set" do
134
+ @dummy.attributes = { :other => "I'm set!",
135
+ :avatar => @file }
136
+
137
+ assert_equal "I'm set!", @dummy.other
138
+ assert ! @dummy.avatar?
139
+ end
140
+
141
+ should "still allow assigment on normal set" do
142
+ @dummy.other = "I'm set!"
143
+ @dummy.avatar = @file
144
+
145
+ assert_equal "I'm set!", @dummy.other
146
+ assert @dummy.avatar?
147
+ end
148
+ end
149
+
150
+ context "with a subclass" do
151
+ setup do
152
+ class ::SubDummy < Dummy; end
153
+ end
154
+
155
+ should "be able to use the attachment from the subclass" do
156
+ assert_nothing_raised do
157
+ @subdummy = SubDummy.create(:avatar => @file)
158
+ end
159
+ end
160
+
161
+ should "be able to see the attachment definition from the subclass's class" do
162
+ assert_equal "tmp/:class/omg/:style.:extension",
163
+ SubDummy.attachment_definitions[:avatar][:path]
164
+ end
165
+
166
+ teardown do
167
+ Object.send(:remove_const, "SubDummy") rescue nil
168
+ end
169
+ end
170
+
171
+ should "have an #avatar method" do
172
+ assert Dummy.new.respond_to?(:avatar)
173
+ end
174
+
175
+ should "have an #avatar= method" do
176
+ assert Dummy.new.respond_to?(:avatar=)
177
+ end
178
+
179
+ context "that is valid" do
180
+ setup do
181
+ @dummy = Dummy.new
182
+ @dummy.avatar = @file
183
+ end
184
+
185
+ should "be valid" do
186
+ assert @dummy.valid?
187
+ end
188
+
189
+ context "then has a validation added that makes it invalid" do
190
+ setup do
191
+ assert @dummy.save
192
+ Dummy.class_eval do
193
+ validates_attachment_content_type :avatar, :content_type => ["text/plain"]
194
+ end
195
+ @dummy2 = Dummy.find(@dummy.id)
196
+ end
197
+
198
+ should "be invalid when reloaded" do
199
+ assert ! @dummy2.valid?, @dummy2.errors.inspect
200
+ end
201
+
202
+ should "be able to call #valid? twice without having duplicate errors" do
203
+ @dummy2.avatar.valid?
204
+ first_errors = @dummy2.avatar.errors
205
+ @dummy2.avatar.valid?
206
+ assert_equal first_errors, @dummy2.avatar.errors
207
+ end
208
+ end
209
+ end
210
+
211
+ context "a validation with an if guard clause" do
212
+ setup do
213
+ Dummy.send(:"validates_attachment_presence", :avatar, :if => lambda{|i| i.foo })
214
+ @dummy = Dummy.new
215
+ @dummy.stubs(:avatar_file_name).returns(nil)
216
+ end
217
+
218
+ should "attempt validation if the guard returns true" do
219
+ @dummy.expects(:foo).returns(true)
220
+ assert ! @dummy.valid?
221
+ end
222
+
223
+ should "not attempt validation if the guard returns false" do
224
+ @dummy.expects(:foo).returns(false)
225
+ assert @dummy.valid?
226
+ end
227
+ end
228
+
229
+ context "a validation with an unless guard clause" do
230
+ setup do
231
+ Dummy.send(:"validates_attachment_presence", :avatar, :unless => lambda{|i| i.foo })
232
+ @dummy = Dummy.new
233
+ @dummy.stubs(:avatar_file_name).returns(nil)
234
+ end
235
+
236
+ should "attempt validation if the guard returns true" do
237
+ @dummy.expects(:foo).returns(false)
238
+ assert ! @dummy.valid?
239
+ end
240
+
241
+ should "not attempt validation if the guard returns false" do
242
+ @dummy.expects(:foo).returns(true)
243
+ assert @dummy.valid?
244
+ end
245
+ end
246
+
247
+ def self.should_validate validation, options, valid_file, invalid_file
248
+ context "with #{validation} validation and #{options.inspect} options" do
249
+ setup do
250
+ Dummy.send(:"validates_attachment_#{validation}", :avatar, options)
251
+ @dummy = Dummy.new
252
+ end
253
+ context "and assigning nil" do
254
+ setup do
255
+ @dummy.avatar = nil
256
+ @dummy.valid?
257
+ end
258
+ if validation == :presence
259
+ should "have an error on the attachment" do
260
+ assert @dummy.errors.on(:avatar_file_name)
261
+ end
262
+ else
263
+ should "not have an error on the attachment" do
264
+ assert_nil @dummy.errors.on(:avatar_file_name), @dummy.errors.full_messages.join(", ")
265
+ end
266
+ end
267
+ end
268
+ context "and assigned a valid file" do
269
+ setup do
270
+ @dummy.avatar = valid_file
271
+ @dummy.valid?
272
+ end
273
+ should "not have an error when assigned a valid file" do
274
+ assert_equal 0, @dummy.errors.length, @dummy.errors.full_messages.join(", ")
275
+ end
276
+ end
277
+ context "and assigned an invalid file" do
278
+ setup do
279
+ @dummy.avatar = invalid_file
280
+ @dummy.valid?
281
+ end
282
+ should "have an error when assigned a valid file" do
283
+ assert @dummy.errors.length > 0
284
+ end
285
+ end
286
+ end
287
+ end
288
+
289
+ [[:presence, {}, "5k.png", nil],
290
+ [:size, {:in => 1..10240}, "5k.png", "12k.png"],
291
+ [:size, {:less_than => 10240}, "5k.png", "12k.png"],
292
+ [:size, {:greater_than => 8096}, "12k.png", "5k.png"],
293
+ [:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"],
294
+ [:content_type, {:content_type => "text/plain"}, "text.txt", "5k.png"],
295
+ [:content_type, {:content_type => %r{image/.*}}, "5k.png", "text.txt"]].each do |args|
296
+ validation, options, valid_file, invalid_file = args
297
+ valid_file &&= File.open(File.join(FIXTURES_DIR, valid_file), "rb")
298
+ invalid_file &&= File.open(File.join(FIXTURES_DIR, invalid_file), "rb")
299
+
300
+ should_validate validation, options, valid_file, invalid_file
301
+ end
302
+
303
+ context "with size validation and less_than 10240 option" do
304
+ context "and assigned an invalid file" do
305
+ setup do
306
+ Dummy.send(:"validates_attachment_size", :avatar, :less_than => 10240)
307
+ @dummy = Dummy.new
308
+ @dummy.avatar &&= File.open(File.join(FIXTURES_DIR, "12k.png"), "rb")
309
+ @dummy.valid?
310
+ end
311
+
312
+ should "have a file size min/max error message" do
313
+ assert_match %r/between 0 and 10240 bytes/, @dummy.errors.on(:avatar_file_size)
314
+ end
315
+ end
316
+ end
317
+
318
+ end
319
+ end