path-paperclip 2.3.3
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 +198 -0
- data/Rakefile +76 -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/generators/paperclip/USAGE +8 -0
- data/lib/generators/paperclip/paperclip_generator.rb +31 -0
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
- data/lib/paperclip.rb +440 -0
- data/lib/paperclip/attachment.rb +401 -0
- data/lib/paperclip/callback_compatability.rb +61 -0
- data/lib/paperclip/geometry.rb +150 -0
- data/lib/paperclip/interpolations.rb +113 -0
- data/lib/paperclip/iostream.rb +59 -0
- data/lib/paperclip/matchers.rb +33 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +75 -0
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
- data/lib/paperclip/processor.rb +49 -0
- data/lib/paperclip/railtie.rb +20 -0
- data/lib/paperclip/storage.rb +258 -0
- data/lib/paperclip/style.rb +90 -0
- data/lib/paperclip/thumbnail.rb +78 -0
- data/lib/paperclip/upfile.rb +52 -0
- data/lib/paperclip/version.rb +3 -0
- data/lib/tasks/paperclip.rake +95 -0
- data/rails/init.rb +2 -0
- data/shoulda_macros/paperclip.rb +119 -0
- data/test/attachment_test.rb +796 -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/ceedub.gif +0 -0
- data/test/fixtures/s3.yml +8 -0
- data/test/fixtures/text.txt +1 -0
- data/test/fixtures/twopage.pdf +0 -0
- data/test/geometry_test.rb +177 -0
- data/test/helper.rb +152 -0
- data/test/integration_test.rb +610 -0
- data/test/interpolations_test.rb +135 -0
- data/test/iostream_test.rb +78 -0
- data/test/matchers/have_attached_file_matcher_test.rb +24 -0
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +54 -0
- data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
- data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
- data/test/paperclip_test.rb +389 -0
- data/test/processor_test.rb +10 -0
- data/test/storage_test.rb +407 -0
- data/test/style_test.rb +141 -0
- data/test/thumbnail_test.rb +227 -0
- data/test/upfile_test.rb +36 -0
- metadata +221 -0
@@ -0,0 +1,135 @@
|
|
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 as the format if defined in the style" do
|
40
|
+
attachment = mock
|
41
|
+
attachment.expects(:styles).returns({:style => {:format => "png"}})
|
42
|
+
attachment.expects(:original_filename).never
|
43
|
+
assert_equal "png", Paperclip::Interpolations.extension(attachment, :style)
|
44
|
+
end
|
45
|
+
|
46
|
+
should "return the extension of the file if content_type is blank" do
|
47
|
+
attachment = mock
|
48
|
+
attachment.expects(:styles).returns({})
|
49
|
+
attachment.expects(:content_type).returns(nil)
|
50
|
+
attachment.expects(:original_filename).returns("one.jpg")
|
51
|
+
assert_equal "jpg", Paperclip::Interpolations.extension(attachment, :style)
|
52
|
+
end
|
53
|
+
|
54
|
+
should "return the default file extension for the content_type" do
|
55
|
+
attachment = mock
|
56
|
+
attachment.expects(:styles).returns({})
|
57
|
+
attachment.expects(:content_type).returns("image/jpeg")
|
58
|
+
attachment.expects(:original_filename).never
|
59
|
+
assert_equal "jpeg", Paperclip::Interpolations.extension(attachment, :style)
|
60
|
+
end
|
61
|
+
|
62
|
+
should "return the id of the attachment" do
|
63
|
+
attachment = mock
|
64
|
+
attachment.expects(:id).returns(23)
|
65
|
+
attachment.expects(:instance).returns(attachment)
|
66
|
+
assert_equal 23, Paperclip::Interpolations.id(attachment, :style)
|
67
|
+
end
|
68
|
+
|
69
|
+
should "return the partitioned id of the attachment" do
|
70
|
+
attachment = mock
|
71
|
+
attachment.expects(:id).returns(23)
|
72
|
+
attachment.expects(:instance).returns(attachment)
|
73
|
+
assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style)
|
74
|
+
end
|
75
|
+
|
76
|
+
should "return the name of the attachment" do
|
77
|
+
attachment = mock
|
78
|
+
attachment.expects(:name).returns("file")
|
79
|
+
assert_equal "files", Paperclip::Interpolations.attachment(attachment, :style)
|
80
|
+
end
|
81
|
+
|
82
|
+
should "return the style" do
|
83
|
+
assert_equal :style, Paperclip::Interpolations.style(:attachment, :style)
|
84
|
+
end
|
85
|
+
|
86
|
+
should "return the default style" do
|
87
|
+
attachment = mock
|
88
|
+
attachment.expects(:default_style).returns(:default_style)
|
89
|
+
assert_equal :default_style, Paperclip::Interpolations.style(attachment, nil)
|
90
|
+
end
|
91
|
+
|
92
|
+
should "reinterpolate :url" do
|
93
|
+
attachment = mock
|
94
|
+
attachment.expects(:options).returns({:url => ":id"})
|
95
|
+
attachment.expects(:url).with(:style, false).returns("1234")
|
96
|
+
assert_equal "1234", Paperclip::Interpolations.url(attachment, :style)
|
97
|
+
end
|
98
|
+
|
99
|
+
should "raise if infinite loop detected reinterpolating :url" do
|
100
|
+
attachment = mock
|
101
|
+
attachment.expects(:options).returns({:url => ":url"})
|
102
|
+
assert_raises(Paperclip::InfiniteInterpolationError){ Paperclip::Interpolations.url(attachment, :style) }
|
103
|
+
end
|
104
|
+
|
105
|
+
should "return the filename as basename.extension" do
|
106
|
+
attachment = mock
|
107
|
+
attachment.expects(:styles).returns({})
|
108
|
+
attachment.expects(:content_type).returns(nil)
|
109
|
+
attachment.expects(:original_filename).returns("one.jpg").times(3)
|
110
|
+
assert_equal "one.jpg", Paperclip::Interpolations.filename(attachment, :style)
|
111
|
+
end
|
112
|
+
|
113
|
+
should "return the filename as basename.extension when format supplied" do
|
114
|
+
attachment = mock
|
115
|
+
attachment.expects(:styles).returns({:style => {:format => :png}})
|
116
|
+
attachment.expects(:original_filename).returns("one.jpg").times(2)
|
117
|
+
assert_equal "one.png", Paperclip::Interpolations.filename(attachment, :style)
|
118
|
+
end
|
119
|
+
|
120
|
+
should "return the timestamp" do
|
121
|
+
now = Time.now
|
122
|
+
attachment = mock
|
123
|
+
attachment.expects(:instance_read).with(:updated_at).returns(now)
|
124
|
+
assert_equal now.to_s, Paperclip::Interpolations.timestamp(attachment, :style)
|
125
|
+
end
|
126
|
+
|
127
|
+
should "call all expected interpolations with the given arguments" do
|
128
|
+
Paperclip::Interpolations.expects(:id).with(:attachment, :style).returns(1234)
|
129
|
+
Paperclip::Interpolations.expects(:attachment).with(:attachment, :style).returns("attachments")
|
130
|
+
Paperclip::Interpolations.expects(:notreal).never
|
131
|
+
Paperclip::Interpolations.expects(:digest).with(:attachment, :style).returns("DIGEST")
|
132
|
+
value = Paperclip::Interpolations.interpolate(":notreal/:id/:attachment/:digest", :attachment, :style)
|
133
|
+
assert_equal ":notreal/1234/attachments/DIGEST", value
|
134
|
+
end
|
135
|
+
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[^stream.*?#{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,24 @@
|
|
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
|
+
context "given a class with no attachment" do
|
12
|
+
should_reject_dummy_class
|
13
|
+
end
|
14
|
+
|
15
|
+
context "given a class with an attachment" do
|
16
|
+
setup do
|
17
|
+
modify_table("dummies"){|d| d.string :avatar_file_name }
|
18
|
+
@dummy_class.has_attached_file :avatar
|
19
|
+
end
|
20
|
+
|
21
|
+
should_accept_dummy_class
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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 :title
|
8
|
+
d.string :avatar_file_name
|
9
|
+
d.string :avatar_content_type
|
10
|
+
end
|
11
|
+
@dummy_class = reset_class "Dummy"
|
12
|
+
@dummy_class.has_attached_file :avatar
|
13
|
+
@matcher = self.class.validate_attachment_content_type(:avatar).
|
14
|
+
allowing(%w(image/png image/jpeg)).
|
15
|
+
rejecting(%w(audio/mp3 application/octet-stream))
|
16
|
+
Paperclip.stubs(:content_type_for_file).returns(nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
context "given a class with no validation" do
|
20
|
+
should_reject_dummy_class
|
21
|
+
end
|
22
|
+
|
23
|
+
context "given a class with a validation that doesn't match" do
|
24
|
+
setup do
|
25
|
+
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{audio/.*}
|
26
|
+
end
|
27
|
+
|
28
|
+
should_reject_dummy_class
|
29
|
+
end
|
30
|
+
|
31
|
+
context "given a class with a matching validation" do
|
32
|
+
setup do
|
33
|
+
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
|
34
|
+
end
|
35
|
+
|
36
|
+
should_accept_dummy_class
|
37
|
+
end
|
38
|
+
|
39
|
+
context "given a class with other validations but matching types" do
|
40
|
+
setup do
|
41
|
+
@dummy_class.validates_presence_of :title
|
42
|
+
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
|
43
|
+
end
|
44
|
+
|
45
|
+
should_accept_dummy_class
|
46
|
+
end
|
47
|
+
|
48
|
+
should "accept a class with a validation" do
|
49
|
+
Paperclip.stubs(:content_type_for_file).returns(nil)
|
50
|
+
@dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
|
51
|
+
assert_accepts @matcher, @dummy_class
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,26 @@
|
|
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
|
+
context "given a class with no validation" do
|
15
|
+
should_reject_dummy_class
|
16
|
+
end
|
17
|
+
|
18
|
+
context "given a class with a matching validation" do
|
19
|
+
setup do
|
20
|
+
@dummy_class.validates_attachment_presence :avatar
|
21
|
+
end
|
22
|
+
|
23
|
+
should_accept_dummy_class
|
24
|
+
end
|
25
|
+
end
|
26
|
+
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
|
+
context "given a class with no validation" do
|
18
|
+
should_reject_dummy_class
|
19
|
+
end
|
20
|
+
|
21
|
+
context "given a class with a validation that's too high" do
|
22
|
+
setup { @dummy_class.validates_attachment_size :avatar, :in => 256..2048 }
|
23
|
+
should_reject_dummy_class
|
24
|
+
end
|
25
|
+
|
26
|
+
context "given a class with a validation that's too low" do
|
27
|
+
setup { @dummy_class.validates_attachment_size :avatar, :in => 0..1024 }
|
28
|
+
should_reject_dummy_class
|
29
|
+
end
|
30
|
+
|
31
|
+
context "given a class with a validation that matches" do
|
32
|
+
setup { @dummy_class.validates_attachment_size :avatar, :in => 256..1024 }
|
33
|
+
should_accept_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
|
+
context "given a class with an upper limit" do
|
41
|
+
setup { @dummy_class.validates_attachment_size :avatar, :less_than => 1 }
|
42
|
+
should_accept_dummy_class
|
43
|
+
end
|
44
|
+
|
45
|
+
context "given a class with no upper limit" do
|
46
|
+
setup { @dummy_class.validates_attachment_size :avatar, :greater_than => 1 }
|
47
|
+
should_accept_dummy_class
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,389 @@
|
|
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
|
+
should "log the command when :log_command is true" do
|
45
|
+
Paperclip.options[:image_magick_path] = nil
|
46
|
+
Paperclip.options[:command_path] = nil
|
47
|
+
Paperclip.stubs(:bit_bucket).returns("/dev/null")
|
48
|
+
Paperclip.expects(:log).with("this 'is the command' 2>/dev/null")
|
49
|
+
Paperclip.expects(:"`").with("this 'is the command' 2>/dev/null")
|
50
|
+
Paperclip.options[:log_command] = true
|
51
|
+
Paperclip.run("this","is the command")
|
52
|
+
end
|
53
|
+
|
54
|
+
should "not log the command when :log_command is false" do
|
55
|
+
Paperclip.options[:image_magick_path] = nil
|
56
|
+
Paperclip.options[:command_path] = nil
|
57
|
+
Paperclip.stubs(:bit_bucket).returns("/dev/null")
|
58
|
+
Paperclip.expects(:log).with("this 'is the command' 2>/dev/null").never
|
59
|
+
Paperclip.expects(:"`").with("this 'is the command' 2>/dev/null")
|
60
|
+
Paperclip.options[:log_command] = false
|
61
|
+
Paperclip.run("this","is the command")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "Calling Paperclip.run when the command is not found" do
|
66
|
+
should "tell you the command isn't there if the shell returns 127" do
|
67
|
+
begin
|
68
|
+
assert_raises(Paperclip::CommandNotFoundError) do
|
69
|
+
`ruby -e 'exit 127'` # Stub $?.exitstatus to be 127, i.e. Command Not Found.
|
70
|
+
Paperclip.stubs(:"`").returns("")
|
71
|
+
Paperclip.run("command")
|
72
|
+
end
|
73
|
+
ensure
|
74
|
+
`ruby -e 'exit 0'` # Unstub $?.exitstatus
|
75
|
+
end
|
76
|
+
end
|
77
|
+
should "tell you the command isn't there if an ENOENT is raised" do
|
78
|
+
assert_raises(Paperclip::CommandNotFoundError) do
|
79
|
+
Paperclip.stubs(:"`").raises(Errno::ENOENT)
|
80
|
+
Paperclip.run("command")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "Paperclip.content_type_for_file" do
|
86
|
+
context "with a string argument" do
|
87
|
+
should "return image/gif for a GIF image" do
|
88
|
+
file = File.join(File.dirname(__FILE__), "fixtures", "ceedub.gif")
|
89
|
+
assert_equal "image/gif", Paperclip.content_type_for_file(file)
|
90
|
+
end
|
91
|
+
|
92
|
+
should "return text/plain for a YAML file" do
|
93
|
+
file = File.join(File.dirname(__FILE__), "fixtures", "s3.yml")
|
94
|
+
assert_equal "text/plain", Paperclip.content_type_for_file(file)
|
95
|
+
end
|
96
|
+
|
97
|
+
should "return application/pdf for a PDF file" do
|
98
|
+
file = File.join(File.dirname(__FILE__), "fixtures", "twopage.pdf")
|
99
|
+
assert_equal "application/pdf", Paperclip.content_type_for_file(file)
|
100
|
+
end
|
101
|
+
|
102
|
+
should "return application/octet-stream for a bad PNG file" do
|
103
|
+
file = File.join(File.dirname(__FILE__), "fixtures", "bad.png")
|
104
|
+
assert_equal "application/octet-stream", Paperclip.content_type_for_file(file)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "with a file argument" do
|
109
|
+
should "return image/gif for a GIF image" do
|
110
|
+
file = File.new(File.join(File.dirname(__FILE__), "fixtures", "ceedub.gif"), "rb")
|
111
|
+
assert_equal "image/gif", Paperclip.content_type_for_file(file)
|
112
|
+
end
|
113
|
+
|
114
|
+
should "return text/plain for a YAML file" do
|
115
|
+
file = File.new(File.join(File.dirname(__FILE__), "fixtures", "s3.yml"), "rb")
|
116
|
+
assert_equal "text/plain", Paperclip.content_type_for_file(file)
|
117
|
+
end
|
118
|
+
|
119
|
+
should "return application/pdf for a PDF file" do
|
120
|
+
file = File.new(File.join(File.dirname(__FILE__), "fixtures", "twopage.pdf"), "rb")
|
121
|
+
assert_equal "application/pdf", Paperclip.content_type_for_file(file)
|
122
|
+
end
|
123
|
+
|
124
|
+
should "return application/octet-stream for a bad PNG file" do
|
125
|
+
file = File.new(File.join(File.dirname(__FILE__), "fixtures", "bad.png"), "rb")
|
126
|
+
assert_equal "application/octet-stream", Paperclip.content_type_for_file(file)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
should "prevent dangerous characters in the command via quoting" do
|
132
|
+
Paperclip.options[:image_magick_path] = nil
|
133
|
+
Paperclip.options[:command_path] = nil
|
134
|
+
Paperclip.options[:log_command] = false
|
135
|
+
Paperclip.options[:swallow_stderr] = false
|
136
|
+
Paperclip.expects(:"`").with(%q[this 'is' 'jack'\''s' '`command`' 'line!'])
|
137
|
+
Paperclip.run("this", "is", "jack's", "`command`", "line!")
|
138
|
+
end
|
139
|
+
|
140
|
+
context "Paperclip.extension_for_content_type" do
|
141
|
+
should "return nil for nil" do
|
142
|
+
assert_nil Paperclip.extension_for_content_type(nil)
|
143
|
+
end
|
144
|
+
|
145
|
+
Hash[
|
146
|
+
nil, nil,
|
147
|
+
"text/plain", "txt",
|
148
|
+
"text/html", "html",
|
149
|
+
"text/csv", "csv",
|
150
|
+
"text/xml", "xml",
|
151
|
+
"text/css", "css",
|
152
|
+
"image/gif", "gif",
|
153
|
+
"image/jpeg", "jpeg",
|
154
|
+
"image/png", "png",
|
155
|
+
"image/tiff", "tiff",
|
156
|
+
"application/pdf", "pdf",
|
157
|
+
"application/octet-stream", "bin",
|
158
|
+
].each do |content_type, extension|
|
159
|
+
should "return #{extension} for #{content_type}" do
|
160
|
+
assert_equal extension, Paperclip.extension_for_content_type(content_type)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context "Paperclip.bit_bucket" do
|
166
|
+
context "on systems without /dev/null" do
|
167
|
+
setup do
|
168
|
+
File.expects(:exists?).with("/dev/null").returns(false)
|
169
|
+
end
|
170
|
+
|
171
|
+
should "return 'NUL'" do
|
172
|
+
assert_equal "NUL", Paperclip.bit_bucket
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context "on systems with /dev/null" do
|
177
|
+
setup do
|
178
|
+
File.expects(:exists?).with("/dev/null").returns(true)
|
179
|
+
end
|
180
|
+
|
181
|
+
should "return '/dev/null'" do
|
182
|
+
assert_equal "/dev/null", Paperclip.bit_bucket
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
should "raise when sent #processor and the name of a class that exists but isn't a subclass of Processor" do
|
188
|
+
assert_raises(Paperclip::PaperclipError){ Paperclip.processor(:attachment) }
|
189
|
+
end
|
190
|
+
|
191
|
+
should "raise when sent #processor and the name of a class that doesn't exist" do
|
192
|
+
assert_raises(NameError){ Paperclip.processor(:boogey_man) }
|
193
|
+
end
|
194
|
+
|
195
|
+
should "return a class when sent #processor and the name of a class under Paperclip" do
|
196
|
+
assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail)
|
197
|
+
end
|
198
|
+
|
199
|
+
context "An ActiveRecord model with an 'avatar' attachment" do
|
200
|
+
setup do
|
201
|
+
rebuild_model :path => "tmp/:class/omg/:style.:extension"
|
202
|
+
@file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
|
203
|
+
end
|
204
|
+
|
205
|
+
teardown { @file.close }
|
206
|
+
|
207
|
+
should "not error when trying to also create a 'blah' attachment" do
|
208
|
+
assert_nothing_raised do
|
209
|
+
Dummy.class_eval do
|
210
|
+
has_attached_file :blah
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context "that is attr_protected" do
|
216
|
+
setup do
|
217
|
+
Dummy.class_eval do
|
218
|
+
attr_protected :avatar
|
219
|
+
end
|
220
|
+
@dummy = Dummy.new
|
221
|
+
end
|
222
|
+
|
223
|
+
should "not assign the avatar on mass-set" do
|
224
|
+
@dummy.attributes = { :other => "I'm set!",
|
225
|
+
:avatar => @file }
|
226
|
+
|
227
|
+
assert_equal "I'm set!", @dummy.other
|
228
|
+
assert ! @dummy.avatar?
|
229
|
+
end
|
230
|
+
|
231
|
+
should "still allow assigment on normal set" do
|
232
|
+
@dummy.other = "I'm set!"
|
233
|
+
@dummy.avatar = @file
|
234
|
+
|
235
|
+
assert_equal "I'm set!", @dummy.other
|
236
|
+
assert @dummy.avatar?
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
context "with a subclass" do
|
241
|
+
setup do
|
242
|
+
class ::SubDummy < Dummy; end
|
243
|
+
end
|
244
|
+
|
245
|
+
should "be able to use the attachment from the subclass" do
|
246
|
+
assert_nothing_raised do
|
247
|
+
@subdummy = SubDummy.create(:avatar => @file)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
should "be able to see the attachment definition from the subclass's class" do
|
252
|
+
assert_equal "tmp/:class/omg/:style.:extension",
|
253
|
+
SubDummy.attachment_definitions[:avatar][:path]
|
254
|
+
end
|
255
|
+
|
256
|
+
teardown do
|
257
|
+
Object.send(:remove_const, "SubDummy") rescue nil
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
should "have an #avatar method" do
|
262
|
+
assert Dummy.new.respond_to?(:avatar)
|
263
|
+
end
|
264
|
+
|
265
|
+
should "have an #avatar= method" do
|
266
|
+
assert Dummy.new.respond_to?(:avatar=)
|
267
|
+
end
|
268
|
+
|
269
|
+
context "that is valid" do
|
270
|
+
setup do
|
271
|
+
@dummy = Dummy.new
|
272
|
+
@dummy.avatar = @file
|
273
|
+
end
|
274
|
+
|
275
|
+
should "be valid" do
|
276
|
+
assert @dummy.valid?
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
context "a validation with an if guard clause" do
|
281
|
+
setup do
|
282
|
+
Dummy.send(:"validates_attachment_presence", :avatar, :if => lambda{|i| i.foo })
|
283
|
+
@dummy = Dummy.new
|
284
|
+
@dummy.stubs(:avatar_file_name).returns(nil)
|
285
|
+
end
|
286
|
+
|
287
|
+
should "attempt validation if the guard returns true" do
|
288
|
+
@dummy.expects(:foo).returns(true)
|
289
|
+
assert ! @dummy.valid?
|
290
|
+
end
|
291
|
+
|
292
|
+
should "not attempt validation if the guard returns false" do
|
293
|
+
@dummy.expects(:foo).returns(false)
|
294
|
+
assert @dummy.valid?
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
context "a validation with an unless guard clause" do
|
299
|
+
setup do
|
300
|
+
Dummy.send(:"validates_attachment_presence", :avatar, :unless => lambda{|i| i.foo })
|
301
|
+
@dummy = Dummy.new
|
302
|
+
@dummy.stubs(:avatar_file_name).returns(nil)
|
303
|
+
end
|
304
|
+
|
305
|
+
should "attempt validation if the guard returns true" do
|
306
|
+
@dummy.expects(:foo).returns(false)
|
307
|
+
assert ! @dummy.valid?
|
308
|
+
end
|
309
|
+
|
310
|
+
should "not attempt validation if the guard returns false" do
|
311
|
+
@dummy.expects(:foo).returns(true)
|
312
|
+
assert @dummy.valid?
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def self.should_validate validation, options, valid_file, invalid_file
|
317
|
+
context "with #{validation} validation and #{options.inspect} options" do
|
318
|
+
setup do
|
319
|
+
rebuild_class
|
320
|
+
Dummy.send(:"validates_attachment_#{validation}", :avatar, options)
|
321
|
+
@dummy = Dummy.new
|
322
|
+
end
|
323
|
+
context "and assigning nil" do
|
324
|
+
setup do
|
325
|
+
@dummy.avatar = nil
|
326
|
+
@dummy.valid?
|
327
|
+
end
|
328
|
+
if validation == :presence
|
329
|
+
should "have an error on the attachment" do
|
330
|
+
assert @dummy.errors[:avatar_file_name]
|
331
|
+
end
|
332
|
+
else
|
333
|
+
should "not have an error on the attachment" do
|
334
|
+
assert @dummy.errors.blank?, @dummy.errors.full_messages.join(", ")
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
context "and assigned a valid file" do
|
339
|
+
setup do
|
340
|
+
@dummy.avatar = valid_file
|
341
|
+
@dummy.valid?
|
342
|
+
end
|
343
|
+
should "not have an error when assigned a valid file" do
|
344
|
+
assert_equal 0, @dummy.errors.length, @dummy.errors.full_messages.join(", ")
|
345
|
+
end
|
346
|
+
end
|
347
|
+
context "and assigned an invalid file" do
|
348
|
+
setup do
|
349
|
+
@dummy.avatar = invalid_file
|
350
|
+
@dummy.valid?
|
351
|
+
end
|
352
|
+
should "have an error when assigned a valid file" do
|
353
|
+
assert @dummy.errors.length > 0
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
[[:presence, {}, "5k.png", nil],
|
360
|
+
[:size, {:in => 1..10240}, "5k.png", "12k.png"],
|
361
|
+
[:size, {:less_than => 10240}, "5k.png", "12k.png"],
|
362
|
+
[:size, {:greater_than => 8096}, "12k.png", "5k.png"],
|
363
|
+
[:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"],
|
364
|
+
[:content_type, {:content_type => "text/plain"}, "text.txt", "5k.png"],
|
365
|
+
[:content_type, {:content_type => %r{image/.*}}, "5k.png", "text.txt"]].each do |args|
|
366
|
+
validation, options, valid_file, invalid_file = args
|
367
|
+
valid_file &&= File.open(File.join(FIXTURES_DIR, valid_file), "rb")
|
368
|
+
invalid_file &&= File.open(File.join(FIXTURES_DIR, invalid_file), "rb")
|
369
|
+
|
370
|
+
should_validate validation, options, valid_file, invalid_file
|
371
|
+
end
|
372
|
+
|
373
|
+
context "with size validation and less_than 10240 option" do
|
374
|
+
context "and assigned an invalid file" do
|
375
|
+
setup do
|
376
|
+
Dummy.send(:"validates_attachment_size", :avatar, :less_than => 10240)
|
377
|
+
@dummy = Dummy.new
|
378
|
+
@dummy.avatar &&= File.open(File.join(FIXTURES_DIR, "12k.png"), "rb")
|
379
|
+
@dummy.valid?
|
380
|
+
end
|
381
|
+
|
382
|
+
should "have a file size min/max error message" do
|
383
|
+
assert [@dummy.errors[:avatar_file_size]].flatten.any?{|error| error =~ %r/between 0 and 10240 bytes/ }
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
end
|
389
|
+
end
|