paperclip_with_versions 2.3.1.1
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.
- data/LICENSE +26 -0
- data/README.rdoc +174 -0
- data/Rakefile +103 -0
- data/generators/paperclip/USAGE +5 -0
- data/generators/paperclip/paperclip_generator.rb +27 -0
- data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
- data/init.rb +1 -0
- data/lib/paperclip.rb +356 -0
- data/lib/paperclip/attachment.rb +414 -0
- data/lib/paperclip/callback_compatability.rb +33 -0
- data/lib/paperclip/geometry.rb +115 -0
- data/lib/paperclip/interpolations.rb +108 -0
- data/lib/paperclip/iostream.rb +58 -0
- data/lib/paperclip/matchers.rb +4 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +49 -0
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +66 -0
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +48 -0
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +83 -0
- data/lib/paperclip/processor.rb +49 -0
- data/lib/paperclip/storage.rb +243 -0
- data/lib/paperclip/thumbnail.rb +73 -0
- data/lib/paperclip/upfile.rb +49 -0
- data/shoulda_macros/paperclip.rb +117 -0
- data/tasks/paperclip_tasks.rake +79 -0
- data/test/attachment_test.rb +815 -0
- data/test/database.yml +4 -0
- data/test/fixtures/12k.png +0 -0
- data/test/fixtures/50x50.png +0 -0
- data/test/fixtures/5k.png +0 -0
- data/test/fixtures/bad.png +1 -0
- data/test/fixtures/s3.yml +8 -0
- data/test/fixtures/text.txt +0 -0
- data/test/fixtures/twopage.pdf +0 -0
- data/test/geometry_test.rb +177 -0
- data/test/helper.rb +108 -0
- data/test/integration_test.rb +483 -0
- data/test/interpolations_test.rb +124 -0
- data/test/iostream_test.rb +71 -0
- data/test/matchers/have_attached_file_matcher_test.rb +21 -0
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +30 -0
- data/test/matchers/validate_attachment_presence_matcher_test.rb +21 -0
- data/test/matchers/validate_attachment_size_matcher_test.rb +50 -0
- data/test/paperclip_test.rb +327 -0
- data/test/processor_test.rb +10 -0
- data/test/storage_test.rb +303 -0
- data/test/thumbnail_test.rb +227 -0
- data/test/upfile_test.rb +28 -0
- metadata +161 -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,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,327 @@
|
|
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
|
+
end
|
216
|
+
|
217
|
+
should "attempt validation if the guard returns true" do
|
218
|
+
@dummy.expects(:foo).returns(true)
|
219
|
+
@dummy.avatar.expects(:validate_presence).returns(nil)
|
220
|
+
@dummy.valid?
|
221
|
+
end
|
222
|
+
|
223
|
+
should "not attempt validation if the guard returns false" do
|
224
|
+
@dummy.expects(:foo).returns(false)
|
225
|
+
@dummy.avatar.expects(:validate_presence).never
|
226
|
+
@dummy.valid?
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
context "a validation with an unless guard clause" do
|
231
|
+
setup do
|
232
|
+
Dummy.send(:"validates_attachment_presence", :avatar, :unless => lambda{|i| i.foo })
|
233
|
+
@dummy = Dummy.new
|
234
|
+
end
|
235
|
+
|
236
|
+
should "attempt validation if the guard returns true" do
|
237
|
+
@dummy.expects(:foo).returns(false)
|
238
|
+
@dummy.avatar.expects(:validate_presence).returns(nil)
|
239
|
+
@dummy.valid?
|
240
|
+
end
|
241
|
+
|
242
|
+
should "not attempt validation if the guard returns false" do
|
243
|
+
@dummy.expects(:foo).returns(true)
|
244
|
+
@dummy.avatar.expects(:validate_presence).never
|
245
|
+
@dummy.valid?
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def self.should_validate validation, options, valid_file, invalid_file
|
250
|
+
context "with #{validation} validation and #{options.inspect} options" do
|
251
|
+
setup do
|
252
|
+
Dummy.send(:"validates_attachment_#{validation}", :avatar, options)
|
253
|
+
@dummy = Dummy.new
|
254
|
+
end
|
255
|
+
context "and assigning nil" do
|
256
|
+
setup do
|
257
|
+
@dummy.avatar = nil
|
258
|
+
@dummy.valid?
|
259
|
+
end
|
260
|
+
if validation == :presence
|
261
|
+
should "have an error on the attachment" do
|
262
|
+
assert @dummy.errors.on(:avatar)
|
263
|
+
end
|
264
|
+
else
|
265
|
+
should "not have an error on the attachment" do
|
266
|
+
assert_nil @dummy.errors.on(:avatar)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
context "and assigned a valid file" do
|
271
|
+
setup do
|
272
|
+
@dummy.avatar = valid_file
|
273
|
+
@dummy.valid?
|
274
|
+
end
|
275
|
+
should "not have an error when assigned a valid file" do
|
276
|
+
assert ! @dummy.avatar.errors.key?(validation)
|
277
|
+
end
|
278
|
+
should "not have an error on the attachment" do
|
279
|
+
assert_nil @dummy.errors.on(:avatar)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
context "and assigned an invalid file" do
|
283
|
+
setup do
|
284
|
+
@dummy.avatar = invalid_file
|
285
|
+
@dummy.valid?
|
286
|
+
end
|
287
|
+
should "have an error when assigned a valid file" do
|
288
|
+
assert_not_nil @dummy.avatar.errors[validation]
|
289
|
+
end
|
290
|
+
should "have an error on the attachment" do
|
291
|
+
assert @dummy.errors.on(:avatar)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
[[:presence, {}, "5k.png", nil],
|
298
|
+
[:size, {:in => 1..10240}, nil, "12k.png"],
|
299
|
+
[:size, {:less_than => 10240}, "5k.png", "12k.png"],
|
300
|
+
[:size, {:greater_than => 8096}, "12k.png", "5k.png"],
|
301
|
+
[:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"],
|
302
|
+
[:content_type, {:content_type => "text/plain"}, "text.txt", "5k.png"],
|
303
|
+
[:content_type, {:content_type => %r{image/.*}}, "5k.png", "text.txt"]].each do |args|
|
304
|
+
validation, options, valid_file, invalid_file = args
|
305
|
+
valid_file &&= File.open(File.join(FIXTURES_DIR, valid_file), "rb")
|
306
|
+
invalid_file &&= File.open(File.join(FIXTURES_DIR, invalid_file), "rb")
|
307
|
+
|
308
|
+
should_validate validation, options, valid_file, invalid_file
|
309
|
+
end
|
310
|
+
|
311
|
+
context "with size validation and less_than 10240 option" do
|
312
|
+
context "and assigned an invalid file" do
|
313
|
+
setup do
|
314
|
+
Dummy.send(:"validates_attachment_size", :avatar, :less_than => 10240)
|
315
|
+
@dummy = Dummy.new
|
316
|
+
@dummy.avatar &&= File.open(File.join(FIXTURES_DIR, "12k.png"), "rb")
|
317
|
+
@dummy.valid?
|
318
|
+
end
|
319
|
+
|
320
|
+
should "have a file size min/max error message" do
|
321
|
+
assert_match /between 0 and 10240 bytes/, @dummy.errors.on(:avatar)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
end
|
327
|
+
end
|