paperclip-youtube 2.3.8.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.md +91 -0
- data/Rakefile +80 -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 +378 -0
- data/lib/paperclip/attachment.rb +376 -0
- data/lib/paperclip/callback_compatability.rb +61 -0
- data/lib/paperclip/command_line.rb +86 -0
- data/lib/paperclip/geometry.rb +115 -0
- data/lib/paperclip/interpolations.rb +130 -0
- data/lib/paperclip/iostream.rb +45 -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 +58 -0
- data/lib/paperclip/railtie.rb +24 -0
- data/lib/paperclip/storage.rb +3 -0
- data/lib/paperclip/storage/filesystem.rb +73 -0
- data/lib/paperclip/storage/s3.rb +192 -0
- data/lib/paperclip/storage/youtube.rb +331 -0
- data/lib/paperclip/style.rb +90 -0
- data/lib/paperclip/thumbnail.rb +79 -0
- data/lib/paperclip/upfile.rb +55 -0
- data/lib/paperclip/version.rb +3 -0
- data/lib/tasks/paperclip.rake +72 -0
- data/rails/init.rb +2 -0
- data/shoulda_macros/paperclip.rb +118 -0
- data/test/attachment_test.rb +921 -0
- data/test/command_line_test.rb +138 -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/fixtures/uppercase.PNG +0 -0
- data/test/geometry_test.rb +177 -0
- data/test/helper.rb +146 -0
- data/test/integration_test.rb +570 -0
- data/test/interpolations_test.rb +143 -0
- data/test/iostream_test.rb +71 -0
- data/test/matchers/have_attached_file_matcher_test.rb +24 -0
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +47 -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 +301 -0
- data/test/processor_test.rb +10 -0
- data/test/storage_test.rb +386 -0
- data/test/style_test.rb +141 -0
- data/test/thumbnail_test.rb +227 -0
- data/test/upfile_test.rb +36 -0
- metadata +195 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module Paperclip
|
2
|
+
# The Upfile module is a convenience module for adding uploaded-file-type methods
|
3
|
+
# to the +File+ class. Useful for testing.
|
4
|
+
# user.avatar = File.new("test/test_avatar.jpg")
|
5
|
+
module Upfile
|
6
|
+
|
7
|
+
# Infer the MIME-type of the file from the extension.
|
8
|
+
def content_type
|
9
|
+
type = (self.path.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
|
10
|
+
case type
|
11
|
+
when %r"jp(e|g|eg)" then "image/jpeg"
|
12
|
+
when %r"tiff?" then "image/tiff"
|
13
|
+
when %r"png", "gif", "bmp" then "image/#{type}"
|
14
|
+
when "txt" then "text/plain"
|
15
|
+
when %r"html?" then "text/html"
|
16
|
+
when "js" then "application/js"
|
17
|
+
when "csv", "xml", "css" then "text/#{type}"
|
18
|
+
else
|
19
|
+
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
|
20
|
+
content_type = (Paperclip.run("file", "-b --mime-type :file", :file => self.path).split(':').last.strip rescue "application/x-#{type}")
|
21
|
+
content_type = "application/x-#{type}" if content_type.match(/\(.*?\)/)
|
22
|
+
content_type
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the file's normal name.
|
27
|
+
def original_filename
|
28
|
+
File.basename(self.path)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the size of the file.
|
32
|
+
def size
|
33
|
+
File.size(self)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if defined? StringIO
|
39
|
+
class StringIO
|
40
|
+
attr_accessor :original_filename, :content_type, :fingerprint
|
41
|
+
def original_filename
|
42
|
+
@original_filename ||= "stringio.txt"
|
43
|
+
end
|
44
|
+
def content_type
|
45
|
+
@content_type ||= "text/plain"
|
46
|
+
end
|
47
|
+
def fingerprint
|
48
|
+
@fingerprint ||= Digest::MD5.hexdigest(self.string)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class File #:nodoc:
|
54
|
+
include Paperclip::Upfile
|
55
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
def obtain_class
|
2
|
+
class_name = ENV['CLASS'] || ENV['class']
|
3
|
+
raise "Must specify CLASS" unless class_name
|
4
|
+
class_name
|
5
|
+
end
|
6
|
+
|
7
|
+
def obtain_attachments(klass)
|
8
|
+
klass = Object.const_get(klass.to_s)
|
9
|
+
name = ENV['ATTACHMENT'] || ENV['attachment']
|
10
|
+
raise "Class #{klass.name} has no attachments specified" unless klass.respond_to?(:attachment_definitions)
|
11
|
+
if !name.blank? && klass.attachment_definitions.keys.include?(name)
|
12
|
+
[ name ]
|
13
|
+
else
|
14
|
+
klass.attachment_definitions.keys
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
namespace :paperclip do
|
19
|
+
desc "Refreshes both metadata and thumbnails."
|
20
|
+
task :refresh => ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"]
|
21
|
+
|
22
|
+
namespace :refresh do
|
23
|
+
desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT)."
|
24
|
+
task :thumbnails => :environment do
|
25
|
+
errors = []
|
26
|
+
klass = obtain_class
|
27
|
+
names = obtain_attachments(klass)
|
28
|
+
names.each do |name|
|
29
|
+
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
30
|
+
result = instance.send(name).reprocess!
|
31
|
+
errors << [instance.id, instance.errors] unless instance.errors.blank?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
errors.each{|e| puts "#{e.first}: #{e.last.full_messages.inspect}" }
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)."
|
38
|
+
task :metadata => :environment do
|
39
|
+
klass = obtain_class
|
40
|
+
names = obtain_attachments(klass)
|
41
|
+
names.each do |name|
|
42
|
+
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
43
|
+
if file = instance.send(name).to_file
|
44
|
+
instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
|
45
|
+
instance.send("#{name}_content_type=", file.content_type.strip)
|
46
|
+
instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
|
47
|
+
instance.save(false)
|
48
|
+
else
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "Cleans out invalid attachments. Useful after you've added new validations."
|
57
|
+
task :clean => :environment do
|
58
|
+
klass = obtain_class
|
59
|
+
names = obtain_attachments(klass)
|
60
|
+
names.each do |name|
|
61
|
+
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
62
|
+
instance.send(name).send(:validate)
|
63
|
+
if instance.send(name).valid?
|
64
|
+
true
|
65
|
+
else
|
66
|
+
instance.send("#{name}=", nil)
|
67
|
+
instance.save
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'paperclip/matchers'
|
2
|
+
|
3
|
+
module Paperclip
|
4
|
+
# =Paperclip Shoulda Macros
|
5
|
+
#
|
6
|
+
# These macros are intended for use with shoulda, and will be included into
|
7
|
+
# your tests automatically. All of the macros use the standard shoulda
|
8
|
+
# assumption that the name of the test is based on the name of the model
|
9
|
+
# you're testing (that is, UserTest is the test for the User model), and
|
10
|
+
# will load that class for testing purposes.
|
11
|
+
module Shoulda
|
12
|
+
include Matchers
|
13
|
+
# This will test whether you have defined your attachment correctly by
|
14
|
+
# checking for all the required fields exist after the definition of the
|
15
|
+
# attachment.
|
16
|
+
def should_have_attached_file name
|
17
|
+
klass = self.name.gsub(/Test$/, '').constantize
|
18
|
+
matcher = have_attached_file name
|
19
|
+
should matcher.description do
|
20
|
+
assert_accepts(matcher, klass)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Tests for validations on the presence of the attachment.
|
25
|
+
def should_validate_attachment_presence name
|
26
|
+
klass = self.name.gsub(/Test$/, '').constantize
|
27
|
+
matcher = validate_attachment_presence name
|
28
|
+
should matcher.description do
|
29
|
+
assert_accepts(matcher, klass)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Tests that you have content_type validations specified. There are two
|
34
|
+
# options, :valid and :invalid. Both accept an array of strings. The
|
35
|
+
# strings should be a list of content types which will pass and fail
|
36
|
+
# validation, respectively.
|
37
|
+
def should_validate_attachment_content_type name, options = {}
|
38
|
+
klass = self.name.gsub(/Test$/, '').constantize
|
39
|
+
valid = [options[:valid]].flatten
|
40
|
+
invalid = [options[:invalid]].flatten
|
41
|
+
matcher = validate_attachment_content_type(name).allowing(valid).rejecting(invalid)
|
42
|
+
should matcher.description do
|
43
|
+
assert_accepts(matcher, klass)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Tests to ensure that you have file size validations turned on. You
|
48
|
+
# can pass the same options to this that you can to
|
49
|
+
# validate_attachment_file_size - :less_than, :greater_than, and :in.
|
50
|
+
# :less_than checks that a file is less than a certain size, :greater_than
|
51
|
+
# checks that a file is more than a certain size, and :in takes a Range or
|
52
|
+
# Array which specifies the lower and upper limits of the file size.
|
53
|
+
def should_validate_attachment_size name, options = {}
|
54
|
+
klass = self.name.gsub(/Test$/, '').constantize
|
55
|
+
min = options[:greater_than] || (options[:in] && options[:in].first) || 0
|
56
|
+
max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
|
57
|
+
range = (min..max)
|
58
|
+
matcher = validate_attachment_size(name).in(range)
|
59
|
+
should matcher.description do
|
60
|
+
assert_accepts(matcher, klass)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Stubs the HTTP PUT for an attachment using S3 storage.
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
# stub_paperclip_s3('user', 'avatar', 'png')
|
68
|
+
def stub_paperclip_s3(model, attachment, extension)
|
69
|
+
definition = model.gsub(" ", "_").classify.constantize.
|
70
|
+
attachment_definitions[attachment.to_sym]
|
71
|
+
|
72
|
+
path = "http://s3.amazonaws.com/:id/#{definition[:path]}"
|
73
|
+
path.gsub!(/:([^\/\.]+)/) do |match|
|
74
|
+
"([^\/\.]+)"
|
75
|
+
end
|
76
|
+
|
77
|
+
begin
|
78
|
+
FakeWeb.register_uri(:put, Regexp.new(path), :body => "OK")
|
79
|
+
rescue NameError
|
80
|
+
raise NameError, "the stub_paperclip_s3 shoulda macro requires the fakeweb gem."
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Stub S3 and return a file for attachment. Best with Factory Girl.
|
85
|
+
# Uses a strict directory convention:
|
86
|
+
#
|
87
|
+
# features/support/paperclip
|
88
|
+
#
|
89
|
+
# This method is used by the Paperclip-provided Cucumber step:
|
90
|
+
#
|
91
|
+
# When I attach a "demo_tape" "mp3" file to a "band" on S3
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
# Factory.define :band_with_demo_tape, :parent => :band do |band|
|
95
|
+
# band.demo_tape { band.paperclip_fixture("band", "demo_tape", "png") }
|
96
|
+
# end
|
97
|
+
def paperclip_fixture(model, attachment, extension)
|
98
|
+
stub_paperclip_s3(model, attachment, extension)
|
99
|
+
base_path = File.join(File.dirname(__FILE__), "..", "..",
|
100
|
+
"features", "support", "paperclip")
|
101
|
+
File.new(File.join(base_path, model, "#{attachment}.#{extension}"))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
if defined?(ActionController::Integration::Session)
|
107
|
+
class ActionController::Integration::Session #:nodoc:
|
108
|
+
include Paperclip::Shoulda
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class Factory
|
113
|
+
include Paperclip::Shoulda #:nodoc:
|
114
|
+
end
|
115
|
+
|
116
|
+
class Test::Unit::TestCase #:nodoc:
|
117
|
+
extend Paperclip::Shoulda
|
118
|
+
end
|
@@ -0,0 +1,921 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require './test/helper'
|
3
|
+
|
4
|
+
class Dummy
|
5
|
+
# This is a dummy class
|
6
|
+
end
|
7
|
+
|
8
|
+
class AttachmentTest < Test::Unit::TestCase
|
9
|
+
should "return the path based on the url by default" do
|
10
|
+
@attachment = attachment :url => "/:class/:id/:basename"
|
11
|
+
@model = @attachment.instance
|
12
|
+
@model.id = 1234
|
13
|
+
@model.avatar_file_name = "fake.jpg"
|
14
|
+
assert_equal "#{Rails.root}/public/fake_models/1234/fake", @attachment.path
|
15
|
+
end
|
16
|
+
|
17
|
+
context "Attachment default_options" do
|
18
|
+
setup do
|
19
|
+
rebuild_model
|
20
|
+
@old_default_options = Paperclip::Attachment.default_options.dup
|
21
|
+
@new_default_options = @old_default_options.merge({
|
22
|
+
:path => "argle/bargle",
|
23
|
+
:url => "fooferon",
|
24
|
+
:default_url => "not here.png"
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
teardown do
|
29
|
+
Paperclip::Attachment.default_options.merge! @old_default_options
|
30
|
+
end
|
31
|
+
|
32
|
+
should "be overrideable" do
|
33
|
+
Paperclip::Attachment.default_options.merge!(@new_default_options)
|
34
|
+
@new_default_options.keys.each do |key|
|
35
|
+
assert_equal @new_default_options[key],
|
36
|
+
Paperclip::Attachment.default_options[key]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "without an Attachment" do
|
41
|
+
setup do
|
42
|
+
@dummy = Dummy.new
|
43
|
+
end
|
44
|
+
|
45
|
+
should "return false when asked exists?" do
|
46
|
+
assert !@dummy.avatar.exists?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "on an Attachment" do
|
51
|
+
setup do
|
52
|
+
@dummy = Dummy.new
|
53
|
+
@attachment = @dummy.avatar
|
54
|
+
end
|
55
|
+
|
56
|
+
Paperclip::Attachment.default_options.keys.each do |key|
|
57
|
+
should "be the default_options for #{key}" do
|
58
|
+
assert_equal @old_default_options[key],
|
59
|
+
@attachment.instance_variable_get("@#{key}"),
|
60
|
+
key
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when redefined" do
|
65
|
+
setup do
|
66
|
+
Paperclip::Attachment.default_options.merge!(@new_default_options)
|
67
|
+
@dummy = Dummy.new
|
68
|
+
@attachment = @dummy.avatar
|
69
|
+
end
|
70
|
+
|
71
|
+
Paperclip::Attachment.default_options.keys.each do |key|
|
72
|
+
should "be the new default_options for #{key}" do
|
73
|
+
assert_equal @new_default_options[key],
|
74
|
+
@attachment.instance_variable_get("@#{key}"),
|
75
|
+
key
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "An attachment with similarly named interpolations" do
|
83
|
+
setup do
|
84
|
+
rebuild_model :path => ":id.omg/:id-bbq/:idwhat/:id_partition.wtf"
|
85
|
+
@dummy = Dummy.new
|
86
|
+
@dummy.stubs(:id).returns(1024)
|
87
|
+
@file = File.new(File.join(File.dirname(__FILE__),
|
88
|
+
"fixtures",
|
89
|
+
"5k.png"), 'rb')
|
90
|
+
@dummy.avatar = @file
|
91
|
+
end
|
92
|
+
|
93
|
+
teardown { @file.close }
|
94
|
+
|
95
|
+
should "make sure that they are interpolated correctly" do
|
96
|
+
assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "An attachment with :timestamp interpolations" do
|
101
|
+
setup do
|
102
|
+
@file = StringIO.new("...")
|
103
|
+
@zone = 'UTC'
|
104
|
+
Time.stubs(:zone).returns(@zone)
|
105
|
+
@zone_default = 'Eastern Time (US & Canada)'
|
106
|
+
Time.stubs(:zone_default).returns(@zone_default)
|
107
|
+
end
|
108
|
+
|
109
|
+
context "using default time zone" do
|
110
|
+
setup do
|
111
|
+
rebuild_model :path => ":timestamp", :use_default_time_zone => true
|
112
|
+
@dummy = Dummy.new
|
113
|
+
@dummy.avatar = @file
|
114
|
+
end
|
115
|
+
|
116
|
+
should "return a time in the default zone" do
|
117
|
+
assert_equal @dummy.avatar_updated_at.in_time_zone(@zone_default).to_s, @dummy.avatar.path
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "using per-thread time zone" do
|
122
|
+
setup do
|
123
|
+
rebuild_model :path => ":timestamp", :use_default_time_zone => false
|
124
|
+
@dummy = Dummy.new
|
125
|
+
@dummy.avatar = @file
|
126
|
+
end
|
127
|
+
|
128
|
+
should "return a time in the per-thread zone" do
|
129
|
+
assert_equal @dummy.avatar_updated_at.in_time_zone(@zone).to_s, @dummy.avatar.path
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "An attachment with :hash interpolations" do
|
135
|
+
setup do
|
136
|
+
@file = StringIO.new("...")
|
137
|
+
end
|
138
|
+
|
139
|
+
should "raise if no secret is provided" do
|
140
|
+
@attachment = attachment :path => ":hash"
|
141
|
+
@attachment.assign @file
|
142
|
+
|
143
|
+
assert_raise ArgumentError do
|
144
|
+
@attachment.path
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context "when secret is set" do
|
149
|
+
setup do
|
150
|
+
@attachment = attachment :path => ":hash", :hash_secret => "w00t"
|
151
|
+
@attachment.stubs(:instance_read).with(:updated_at).returns(Time.at(1234567890))
|
152
|
+
@attachment.stubs(:instance_read).with(:file_name).returns("bla.txt")
|
153
|
+
@attachment.instance.id = 1234
|
154
|
+
@attachment.assign @file
|
155
|
+
end
|
156
|
+
|
157
|
+
should "interpolate the hash data" do
|
158
|
+
@attachment.expects(:interpolate).with(@attachment.options[:hash_data],anything).returns("interpolated_stuff")
|
159
|
+
@attachment.hash
|
160
|
+
end
|
161
|
+
|
162
|
+
should "result in the correct interpolation" do
|
163
|
+
assert_equal "fake_models/avatars/1234/original/1234567890", @attachment.send(:interpolate,@attachment.options[:hash_data])
|
164
|
+
end
|
165
|
+
|
166
|
+
should "result in a correct hash" do
|
167
|
+
assert_equal "d22b617d1bf10016aa7d046d16427ae203f39fce", @attachment.path
|
168
|
+
end
|
169
|
+
|
170
|
+
should "generate a hash digest with the correct style" do
|
171
|
+
OpenSSL::HMAC.expects(:hexdigest).with(anything, anything, "fake_models/avatars/1234/medium/1234567890")
|
172
|
+
@attachment.path("medium")
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context "An attachment with a :rails_env interpolation" do
|
178
|
+
setup do
|
179
|
+
@rails_env = "blah"
|
180
|
+
@id = 1024
|
181
|
+
rebuild_model :path => ":rails_env/:id.png"
|
182
|
+
@dummy = Dummy.new
|
183
|
+
@dummy.stubs(:id).returns(@id)
|
184
|
+
@file = StringIO.new(".")
|
185
|
+
@dummy.avatar = @file
|
186
|
+
Rails.stubs(:env).returns(@rails_env)
|
187
|
+
end
|
188
|
+
|
189
|
+
should "return the proper path" do
|
190
|
+
assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context "An attachment with a default style and an extension interpolation" do
|
195
|
+
setup do
|
196
|
+
@attachment = attachment :path => ":basename.:extension",
|
197
|
+
:styles => { :default => ["100x100", :png] },
|
198
|
+
:default_style => :default
|
199
|
+
@file = StringIO.new("...")
|
200
|
+
@file.stubs(:original_filename).returns("file.jpg")
|
201
|
+
end
|
202
|
+
should "return the right extension for the path" do
|
203
|
+
@attachment.assign(@file)
|
204
|
+
assert_equal "file.png", @attachment.path
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "An attachment with :convert_options" do
|
209
|
+
setup do
|
210
|
+
rebuild_model :styles => {
|
211
|
+
:thumb => "100x100",
|
212
|
+
:large => "400x400"
|
213
|
+
},
|
214
|
+
:convert_options => {
|
215
|
+
:all => "-do_stuff",
|
216
|
+
:thumb => "-thumbnailize"
|
217
|
+
}
|
218
|
+
@dummy = Dummy.new
|
219
|
+
@dummy.avatar
|
220
|
+
end
|
221
|
+
|
222
|
+
should "report the correct options when sent #extra_options_for(:thumb)" do
|
223
|
+
assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
|
224
|
+
end
|
225
|
+
|
226
|
+
should "report the correct options when sent #extra_options_for(:large)" do
|
227
|
+
assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "An attachment with :convert_options that is a proc" do
|
232
|
+
setup do
|
233
|
+
rebuild_model :styles => {
|
234
|
+
:thumb => "100x100",
|
235
|
+
:large => "400x400"
|
236
|
+
},
|
237
|
+
:convert_options => {
|
238
|
+
:all => lambda{|i| i.all },
|
239
|
+
:thumb => lambda{|i| i.thumb }
|
240
|
+
}
|
241
|
+
Dummy.class_eval do
|
242
|
+
def all; "-all"; end
|
243
|
+
def thumb; "-thumb"; end
|
244
|
+
end
|
245
|
+
@dummy = Dummy.new
|
246
|
+
@dummy.avatar
|
247
|
+
end
|
248
|
+
|
249
|
+
should "report the correct options when sent #extra_options_for(:thumb)" do
|
250
|
+
assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect
|
251
|
+
end
|
252
|
+
|
253
|
+
should "report the correct options when sent #extra_options_for(:large)" do
|
254
|
+
assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
context "An attachment with :path that is a proc" do
|
259
|
+
setup do
|
260
|
+
rebuild_model :path => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
|
261
|
+
|
262
|
+
@file = File.new(File.join(File.dirname(__FILE__),
|
263
|
+
"fixtures",
|
264
|
+
"5k.png"), 'rb')
|
265
|
+
@dummyA = Dummy.new(:other => 'a')
|
266
|
+
@dummyA.avatar = @file
|
267
|
+
@dummyB = Dummy.new(:other => 'b')
|
268
|
+
@dummyB.avatar = @file
|
269
|
+
end
|
270
|
+
|
271
|
+
teardown { @file.close }
|
272
|
+
|
273
|
+
should "return correct path" do
|
274
|
+
assert_equal "path/a.png", @dummyA.avatar.path
|
275
|
+
assert_equal "path/b.png", @dummyB.avatar.path
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
context "An attachment with :styles that is a proc" do
|
280
|
+
setup do
|
281
|
+
rebuild_model :styles => lambda{ |attachment| {:thumb => "50x50#", :large => "400x400"} }
|
282
|
+
|
283
|
+
@attachment = Dummy.new.avatar
|
284
|
+
end
|
285
|
+
|
286
|
+
should "have the correct geometry" do
|
287
|
+
assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
context "An attachment with :url that is a proc" do
|
292
|
+
setup do
|
293
|
+
rebuild_model :url => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
|
294
|
+
|
295
|
+
@file = File.new(File.join(File.dirname(__FILE__),
|
296
|
+
"fixtures",
|
297
|
+
"5k.png"), 'rb')
|
298
|
+
@dummyA = Dummy.new(:other => 'a')
|
299
|
+
@dummyA.avatar = @file
|
300
|
+
@dummyB = Dummy.new(:other => 'b')
|
301
|
+
@dummyB.avatar = @file
|
302
|
+
end
|
303
|
+
|
304
|
+
teardown { @file.close }
|
305
|
+
|
306
|
+
should "return correct url" do
|
307
|
+
assert_equal "path/a.png", @dummyA.avatar.url(:original, false)
|
308
|
+
assert_equal "path/b.png", @dummyB.avatar.url(:original, false)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
geometry_specs = [
|
313
|
+
[ lambda{|z| "50x50#" }, :png ],
|
314
|
+
lambda{|z| "50x50#" },
|
315
|
+
{ :geometry => lambda{|z| "50x50#" } }
|
316
|
+
]
|
317
|
+
geometry_specs.each do |geometry_spec|
|
318
|
+
context "An attachment geometry like #{geometry_spec}" do
|
319
|
+
setup do
|
320
|
+
rebuild_model :styles => { :normal => geometry_spec }
|
321
|
+
@attachment = Dummy.new.avatar
|
322
|
+
end
|
323
|
+
|
324
|
+
context "when assigned" do
|
325
|
+
setup do
|
326
|
+
@file = StringIO.new(".")
|
327
|
+
@attachment.assign(@file)
|
328
|
+
end
|
329
|
+
|
330
|
+
should "have the correct geometry" do
|
331
|
+
assert_equal "50x50#", @attachment.styles[:normal][:geometry]
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
context "An attachment with both 'normal' and hash-style styles" do
|
338
|
+
setup do
|
339
|
+
rebuild_model :styles => {
|
340
|
+
:normal => ["50x50#", :png],
|
341
|
+
:hash => { :geometry => "50x50#", :format => :png }
|
342
|
+
}
|
343
|
+
@dummy = Dummy.new
|
344
|
+
@attachment = @dummy.avatar
|
345
|
+
end
|
346
|
+
|
347
|
+
[:processors, :whiny, :convert_options, :geometry, :format].each do |field|
|
348
|
+
should "have the same #{field} field" do
|
349
|
+
assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field]
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
context "An attachment with :processors that is a proc" do
|
355
|
+
setup do
|
356
|
+
rebuild_model :styles => { :normal => '' }, :processors => lambda { |a| [ :test ] }
|
357
|
+
@attachment = Dummy.new.avatar
|
358
|
+
end
|
359
|
+
|
360
|
+
context "when assigned" do
|
361
|
+
setup do
|
362
|
+
@attachment.assign(StringIO.new("."))
|
363
|
+
end
|
364
|
+
|
365
|
+
should "have the correct processors" do
|
366
|
+
assert_equal [ :test ], @attachment.styles[:normal][:processors]
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
context "An attachment with erroring processor" do
|
372
|
+
setup do
|
373
|
+
rebuild_model :processor => [:thumbnail], :styles => { :small => '' }, :whiny_thumbnails => true
|
374
|
+
@dummy = Dummy.new
|
375
|
+
Paperclip::Thumbnail.expects(:make).raises(Paperclip::PaperclipError, "cannot be processed.")
|
376
|
+
@file = StringIO.new("...")
|
377
|
+
@file.stubs(:to_tempfile).returns(@file)
|
378
|
+
@dummy.avatar = @file
|
379
|
+
end
|
380
|
+
|
381
|
+
should "correctly forward processing error message to the instance" do
|
382
|
+
@dummy.valid?
|
383
|
+
assert_contains @dummy.errors.full_messages, "Avatar cannot be processed."
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
context "An attachment with multiple processors" do
|
388
|
+
setup do
|
389
|
+
class Paperclip::Test < Paperclip::Processor; end
|
390
|
+
@style_params = { :once => {:one => 1, :two => 2} }
|
391
|
+
rebuild_model :processors => [:thumbnail, :test], :styles => @style_params
|
392
|
+
@dummy = Dummy.new
|
393
|
+
@file = StringIO.new("...")
|
394
|
+
@file.stubs(:to_tempfile).returns(@file)
|
395
|
+
Paperclip::Test.stubs(:make).returns(@file)
|
396
|
+
Paperclip::Thumbnail.stubs(:make).returns(@file)
|
397
|
+
end
|
398
|
+
|
399
|
+
context "when assigned" do
|
400
|
+
setup { @dummy.avatar = @file }
|
401
|
+
|
402
|
+
before_should "call #make on all specified processors" do
|
403
|
+
Paperclip::Thumbnail.expects(:make).with(any_parameters).returns(@file)
|
404
|
+
Paperclip::Test.expects(:make).with(any_parameters).returns(@file)
|
405
|
+
end
|
406
|
+
|
407
|
+
before_should "call #make with the right parameters passed as second argument" do
|
408
|
+
expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""})
|
409
|
+
Paperclip::Thumbnail.expects(:make).with(anything, expected_params, anything).returns(@file)
|
410
|
+
end
|
411
|
+
|
412
|
+
before_should "call #make with attachment passed as third argument" do
|
413
|
+
Paperclip::Test.expects(:make).with(anything, anything, @dummy.avatar).returns(@file)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
should "include the filesystem module when loading the filesystem storage" do
|
419
|
+
rebuild_model :storage => :filesystem
|
420
|
+
@dummy = Dummy.new
|
421
|
+
assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
|
422
|
+
end
|
423
|
+
|
424
|
+
should "include the filesystem module even if capitalization is wrong" do
|
425
|
+
rebuild_model :storage => :FileSystem
|
426
|
+
@dummy = Dummy.new
|
427
|
+
assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
|
428
|
+
end
|
429
|
+
|
430
|
+
should "raise an error if you try to include a storage module that doesn't exist" do
|
431
|
+
rebuild_model :storage => :not_here
|
432
|
+
@dummy = Dummy.new
|
433
|
+
assert_raises(Paperclip::StorageMethodNotFound) do
|
434
|
+
@dummy.avatar
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
context "An attachment with styles but no processors defined" do
|
439
|
+
setup do
|
440
|
+
rebuild_model :processors => [], :styles => {:something => '1'}
|
441
|
+
@dummy = Dummy.new
|
442
|
+
@file = StringIO.new("...")
|
443
|
+
end
|
444
|
+
should "raise when assigned to" do
|
445
|
+
assert_raises(RuntimeError){ @dummy.avatar = @file }
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
context "An attachment without styles and with no processors defined" do
|
450
|
+
setup do
|
451
|
+
rebuild_model :processors => [], :styles => {}
|
452
|
+
@dummy = Dummy.new
|
453
|
+
@file = StringIO.new("...")
|
454
|
+
end
|
455
|
+
should "not raise when assigned to" do
|
456
|
+
@dummy.avatar = @file
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
context "Assigning an attachment with post_process hooks" do
|
461
|
+
setup do
|
462
|
+
rebuild_class :styles => { :something => "100x100#" }
|
463
|
+
Dummy.class_eval do
|
464
|
+
before_avatar_post_process :do_before_avatar
|
465
|
+
after_avatar_post_process :do_after_avatar
|
466
|
+
before_post_process :do_before_all
|
467
|
+
after_post_process :do_after_all
|
468
|
+
def do_before_avatar; end
|
469
|
+
def do_after_avatar; end
|
470
|
+
def do_before_all; end
|
471
|
+
def do_after_all; end
|
472
|
+
end
|
473
|
+
@file = StringIO.new(".")
|
474
|
+
@file.stubs(:to_tempfile).returns(@file)
|
475
|
+
@dummy = Dummy.new
|
476
|
+
Paperclip::Thumbnail.stubs(:make).returns(@file)
|
477
|
+
@attachment = @dummy.avatar
|
478
|
+
end
|
479
|
+
|
480
|
+
should "call the defined callbacks when assigned" do
|
481
|
+
@dummy.expects(:do_before_avatar).with()
|
482
|
+
@dummy.expects(:do_after_avatar).with()
|
483
|
+
@dummy.expects(:do_before_all).with()
|
484
|
+
@dummy.expects(:do_after_all).with()
|
485
|
+
Paperclip::Thumbnail.expects(:make).returns(@file)
|
486
|
+
@dummy.avatar = @file
|
487
|
+
end
|
488
|
+
|
489
|
+
should "not cancel the processing if a before_post_process returns nil" do
|
490
|
+
@dummy.expects(:do_before_avatar).with().returns(nil)
|
491
|
+
@dummy.expects(:do_after_avatar).with()
|
492
|
+
@dummy.expects(:do_before_all).with().returns(nil)
|
493
|
+
@dummy.expects(:do_after_all).with()
|
494
|
+
Paperclip::Thumbnail.expects(:make).returns(@file)
|
495
|
+
@dummy.avatar = @file
|
496
|
+
end
|
497
|
+
|
498
|
+
should "cancel the processing if a before_post_process returns false" do
|
499
|
+
@dummy.expects(:do_before_avatar).never
|
500
|
+
@dummy.expects(:do_after_avatar).never
|
501
|
+
@dummy.expects(:do_before_all).with().returns(false)
|
502
|
+
@dummy.expects(:do_after_all)
|
503
|
+
Paperclip::Thumbnail.expects(:make).never
|
504
|
+
@dummy.avatar = @file
|
505
|
+
end
|
506
|
+
|
507
|
+
should "cancel the processing if a before_avatar_post_process returns false" do
|
508
|
+
@dummy.expects(:do_before_avatar).with().returns(false)
|
509
|
+
@dummy.expects(:do_after_avatar)
|
510
|
+
@dummy.expects(:do_before_all).with().returns(true)
|
511
|
+
@dummy.expects(:do_after_all)
|
512
|
+
Paperclip::Thumbnail.expects(:make).never
|
513
|
+
@dummy.avatar = @file
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
context "Assigning an attachment" do
|
518
|
+
setup do
|
519
|
+
rebuild_model :styles => { :something => "100x100#" }
|
520
|
+
@file = StringIO.new(".")
|
521
|
+
@file.stubs(:original_filename).returns("5k.png\n\n")
|
522
|
+
@file.stubs(:content_type).returns("image/png\n\n")
|
523
|
+
@file.stubs(:to_tempfile).returns(@file)
|
524
|
+
@dummy = Dummy.new
|
525
|
+
Paperclip::Thumbnail.expects(:make).returns(@file)
|
526
|
+
@attachment = @dummy.avatar
|
527
|
+
@dummy.avatar = @file
|
528
|
+
end
|
529
|
+
|
530
|
+
should "strip whitespace from original_filename field" do
|
531
|
+
assert_equal "5k.png", @dummy.avatar.original_filename
|
532
|
+
end
|
533
|
+
|
534
|
+
should "strip whitespace from content_type field" do
|
535
|
+
assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
context "Attachment with strange letters" do
|
540
|
+
setup do
|
541
|
+
rebuild_model
|
542
|
+
|
543
|
+
@not_file = mock("not_file")
|
544
|
+
@tempfile = mock("tempfile")
|
545
|
+
@not_file.stubs(:nil?).returns(false)
|
546
|
+
@not_file.expects(:size).returns(10)
|
547
|
+
@tempfile.expects(:size).returns(10)
|
548
|
+
@not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n")
|
549
|
+
@not_file.expects(:content_type).returns("image/png\r\n")
|
550
|
+
|
551
|
+
@dummy = Dummy.new
|
552
|
+
@attachment = @dummy.avatar
|
553
|
+
@attachment.expects(:valid_assignment?).with(@not_file).returns(true)
|
554
|
+
@attachment.expects(:queue_existing_for_delete)
|
555
|
+
@attachment.expects(:post_process)
|
556
|
+
@attachment.expects(:to_tempfile).returns(@tempfile)
|
557
|
+
@attachment.expects(:generate_fingerprint).with(@tempfile).returns("12345")
|
558
|
+
@attachment.expects(:generate_fingerprint).with(@not_file).returns("12345")
|
559
|
+
@dummy.avatar = @not_file
|
560
|
+
end
|
561
|
+
|
562
|
+
should "not remove strange letters" do
|
563
|
+
assert_equal "sheep_say_bæ.png", @dummy.avatar.original_filename
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
context "Attachment with uppercase extension and a default style" do
|
568
|
+
setup do
|
569
|
+
@old_defaults = Paperclip::Attachment.default_options.dup
|
570
|
+
Paperclip::Attachment.default_options.merge!({
|
571
|
+
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
572
|
+
})
|
573
|
+
FileUtils.rm_rf("tmp")
|
574
|
+
rebuild_model
|
575
|
+
@instance = Dummy.new
|
576
|
+
@instance.stubs(:id).returns 123
|
577
|
+
|
578
|
+
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "uppercase.PNG"), 'rb')
|
579
|
+
|
580
|
+
styles = {:styles => { :large => ["400x400", :jpg],
|
581
|
+
:medium => ["100x100", :jpg],
|
582
|
+
:small => ["32x32#", :jpg]},
|
583
|
+
:default_style => :small}
|
584
|
+
@attachment = Paperclip::Attachment.new(:avatar,
|
585
|
+
@instance,
|
586
|
+
styles)
|
587
|
+
now = Time.now
|
588
|
+
Time.stubs(:now).returns(now)
|
589
|
+
@attachment.assign(@file)
|
590
|
+
@attachment.save
|
591
|
+
end
|
592
|
+
|
593
|
+
teardown do
|
594
|
+
@file.close
|
595
|
+
Paperclip::Attachment.default_options.merge!(@old_defaults)
|
596
|
+
end
|
597
|
+
|
598
|
+
should "should have matching to_s and url methods" do
|
599
|
+
file = @attachment.to_file
|
600
|
+
assert file
|
601
|
+
assert_match @attachment.to_s, @attachment.url
|
602
|
+
assert_match @attachment.to_s(:small), @attachment.url(:small)
|
603
|
+
file.close
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
context "An attachment" do
|
608
|
+
setup do
|
609
|
+
@old_defaults = Paperclip::Attachment.default_options.dup
|
610
|
+
Paperclip::Attachment.default_options.merge!({
|
611
|
+
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
612
|
+
})
|
613
|
+
FileUtils.rm_rf("tmp")
|
614
|
+
rebuild_model
|
615
|
+
@instance = Dummy.new
|
616
|
+
@instance.stubs(:id).returns 123
|
617
|
+
@attachment = Paperclip::Attachment.new(:avatar, @instance)
|
618
|
+
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
|
619
|
+
end
|
620
|
+
|
621
|
+
teardown do
|
622
|
+
@file.close
|
623
|
+
Paperclip::Attachment.default_options.merge!(@old_defaults)
|
624
|
+
end
|
625
|
+
|
626
|
+
should "raise if there are not the correct columns when you try to assign" do
|
627
|
+
@other_attachment = Paperclip::Attachment.new(:not_here, @instance)
|
628
|
+
assert_raises(Paperclip::PaperclipError) do
|
629
|
+
@other_attachment.assign(@file)
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
should "return its default_url when no file assigned" do
|
634
|
+
assert @attachment.to_file.nil?
|
635
|
+
assert_equal "/avatars/original/missing.png", @attachment.url
|
636
|
+
assert_equal "/avatars/blah/missing.png", @attachment.url(:blah)
|
637
|
+
end
|
638
|
+
|
639
|
+
should "return nil as path when no file assigned" do
|
640
|
+
assert @attachment.to_file.nil?
|
641
|
+
assert_equal nil, @attachment.path
|
642
|
+
assert_equal nil, @attachment.path(:blah)
|
643
|
+
end
|
644
|
+
|
645
|
+
context "with a file assigned in the database" do
|
646
|
+
setup do
|
647
|
+
@attachment.stubs(:instance_read).with(:file_name).returns("5k.png")
|
648
|
+
@attachment.stubs(:instance_read).with(:content_type).returns("image/png")
|
649
|
+
@attachment.stubs(:instance_read).with(:file_size).returns(12345)
|
650
|
+
dtnow = DateTime.now
|
651
|
+
@now = Time.now
|
652
|
+
Time.stubs(:now).returns(@now)
|
653
|
+
@attachment.stubs(:instance_read).with(:updated_at).returns(dtnow)
|
654
|
+
end
|
655
|
+
|
656
|
+
should "return a correct url even if the file does not exist" do
|
657
|
+
assert_nil @attachment.to_file
|
658
|
+
assert_match %r{^/system/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
|
659
|
+
end
|
660
|
+
|
661
|
+
should "make sure the updated_at mtime is in the url if it is defined" do
|
662
|
+
assert_match %r{#{@now.to_i}$}, @attachment.url(:blah)
|
663
|
+
end
|
664
|
+
|
665
|
+
should "make sure the updated_at mtime is NOT in the url if false is passed to the url method" do
|
666
|
+
assert_no_match %r{#{@now.to_i}$}, @attachment.url(:blah, false)
|
667
|
+
end
|
668
|
+
|
669
|
+
context "with the updated_at field removed" do
|
670
|
+
setup do
|
671
|
+
@attachment.stubs(:instance_read).with(:updated_at).returns(nil)
|
672
|
+
end
|
673
|
+
|
674
|
+
should "only return the url without the updated_at when sent #url" do
|
675
|
+
assert_match "/avatars/#{@instance.id}/blah/5k.png", @attachment.url(:blah)
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
should "return the proper path when filename has a single .'s" do
|
680
|
+
assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.png"), File.expand_path(@attachment.path)
|
681
|
+
end
|
682
|
+
|
683
|
+
should "return the proper path when filename has multiple .'s" do
|
684
|
+
@attachment.stubs(:instance_read).with(:file_name).returns("5k.old.png")
|
685
|
+
assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png"), File.expand_path(@attachment.path)
|
686
|
+
end
|
687
|
+
|
688
|
+
context "when expecting three styles" do
|
689
|
+
setup do
|
690
|
+
styles = {:styles => { :large => ["400x400", :png],
|
691
|
+
:medium => ["100x100", :gif],
|
692
|
+
:small => ["32x32#", :jpg]}}
|
693
|
+
@attachment = Paperclip::Attachment.new(:avatar,
|
694
|
+
@instance,
|
695
|
+
styles)
|
696
|
+
end
|
697
|
+
|
698
|
+
context "and assigned a file" do
|
699
|
+
setup do
|
700
|
+
now = Time.now
|
701
|
+
Time.stubs(:now).returns(now)
|
702
|
+
@attachment.assign(@file)
|
703
|
+
end
|
704
|
+
|
705
|
+
should "be dirty" do
|
706
|
+
assert @attachment.dirty?
|
707
|
+
end
|
708
|
+
|
709
|
+
context "and saved" do
|
710
|
+
setup do
|
711
|
+
@attachment.save
|
712
|
+
end
|
713
|
+
|
714
|
+
should "return the real url" do
|
715
|
+
file = @attachment.to_file
|
716
|
+
assert file
|
717
|
+
assert_match %r{^/system/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
|
718
|
+
assert_match %r{^/system/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
|
719
|
+
file.close
|
720
|
+
end
|
721
|
+
|
722
|
+
should "commit the files to disk" do
|
723
|
+
[:large, :medium, :small].each do |style|
|
724
|
+
io = @attachment.to_file(style)
|
725
|
+
# p "in commit to disk test, io is #{io.inspect} and @instance.id is #{@instance.id}"
|
726
|
+
assert File.exists?(io.path)
|
727
|
+
assert ! io.is_a?(::Tempfile)
|
728
|
+
io.close
|
729
|
+
end
|
730
|
+
end
|
731
|
+
|
732
|
+
should "save the files as the right formats and sizes" do
|
733
|
+
[[:large, 400, 61, "PNG"],
|
734
|
+
[:medium, 100, 15, "GIF"],
|
735
|
+
[:small, 32, 32, "JPEG"]].each do |style|
|
736
|
+
cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"]
|
737
|
+
out = `#{cmd}`
|
738
|
+
width, height, size, format = out.split(" ")
|
739
|
+
assert_equal style[1].to_s, width.to_s
|
740
|
+
assert_equal style[2].to_s, height.to_s
|
741
|
+
assert_equal style[3].to_s, format.to_s
|
742
|
+
end
|
743
|
+
end
|
744
|
+
|
745
|
+
should "still have its #file attribute not be nil" do
|
746
|
+
assert ! (file = @attachment.to_file).nil?
|
747
|
+
file.close
|
748
|
+
end
|
749
|
+
|
750
|
+
context "and trying to delete" do
|
751
|
+
setup do
|
752
|
+
@existing_names = @attachment.styles.keys.collect do |style|
|
753
|
+
@attachment.path(style)
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
should "delete the files after assigning nil" do
|
758
|
+
@attachment.expects(:instance_write).with(:file_name, nil)
|
759
|
+
@attachment.expects(:instance_write).with(:content_type, nil)
|
760
|
+
@attachment.expects(:instance_write).with(:file_size, nil)
|
761
|
+
@attachment.expects(:instance_write).with(:updated_at, nil)
|
762
|
+
@attachment.assign nil
|
763
|
+
@attachment.save
|
764
|
+
@existing_names.each{|f| assert ! File.exists?(f) }
|
765
|
+
end
|
766
|
+
|
767
|
+
should "delete the files when you call #clear and #save" do
|
768
|
+
@attachment.expects(:instance_write).with(:file_name, nil)
|
769
|
+
@attachment.expects(:instance_write).with(:content_type, nil)
|
770
|
+
@attachment.expects(:instance_write).with(:file_size, nil)
|
771
|
+
@attachment.expects(:instance_write).with(:updated_at, nil)
|
772
|
+
@attachment.clear
|
773
|
+
@attachment.save
|
774
|
+
@existing_names.each{|f| assert ! File.exists?(f) }
|
775
|
+
end
|
776
|
+
|
777
|
+
should "delete the files when you call #delete" do
|
778
|
+
@attachment.expects(:instance_write).with(:file_name, nil)
|
779
|
+
@attachment.expects(:instance_write).with(:content_type, nil)
|
780
|
+
@attachment.expects(:instance_write).with(:file_size, nil)
|
781
|
+
@attachment.expects(:instance_write).with(:updated_at, nil)
|
782
|
+
@attachment.destroy
|
783
|
+
@existing_names.each{|f| assert ! File.exists?(f) }
|
784
|
+
end
|
785
|
+
end
|
786
|
+
end
|
787
|
+
end
|
788
|
+
end
|
789
|
+
|
790
|
+
end
|
791
|
+
|
792
|
+
context "when trying a nonexistant storage type" do
|
793
|
+
setup do
|
794
|
+
rebuild_model :storage => :not_here
|
795
|
+
end
|
796
|
+
|
797
|
+
should "not be able to find the module" do
|
798
|
+
assert_raise(Paperclip::StorageMethodNotFound){ Dummy.new.avatar }
|
799
|
+
end
|
800
|
+
end
|
801
|
+
end
|
802
|
+
|
803
|
+
context "An attachment with only a avatar_file_name column" do
|
804
|
+
setup do
|
805
|
+
ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
|
806
|
+
table.column :avatar_file_name, :string
|
807
|
+
end
|
808
|
+
rebuild_class
|
809
|
+
@dummy = Dummy.new
|
810
|
+
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
|
811
|
+
end
|
812
|
+
|
813
|
+
teardown { @file.close }
|
814
|
+
|
815
|
+
should "not error when assigned an attachment" do
|
816
|
+
assert_nothing_raised { @dummy.avatar = @file }
|
817
|
+
end
|
818
|
+
|
819
|
+
should "return the time when sent #avatar_updated_at" do
|
820
|
+
now = Time.now
|
821
|
+
Time.stubs(:now).returns(now)
|
822
|
+
@dummy.avatar = @file
|
823
|
+
assert_equal now.to_i, @dummy.avatar.updated_at.to_i
|
824
|
+
end
|
825
|
+
|
826
|
+
should "return nil when reloaded and sent #avatar_updated_at" do
|
827
|
+
@dummy.save
|
828
|
+
@dummy.reload
|
829
|
+
assert_nil @dummy.avatar.updated_at
|
830
|
+
end
|
831
|
+
|
832
|
+
should "return the right value when sent #avatar_file_size" do
|
833
|
+
@dummy.avatar = @file
|
834
|
+
assert_equal @file.size, @dummy.avatar.size
|
835
|
+
end
|
836
|
+
|
837
|
+
context "and avatar_updated_at column" do
|
838
|
+
setup do
|
839
|
+
ActiveRecord::Base.connection.add_column :dummies, :avatar_updated_at, :timestamp
|
840
|
+
rebuild_class
|
841
|
+
@dummy = Dummy.new
|
842
|
+
end
|
843
|
+
|
844
|
+
should "not error when assigned an attachment" do
|
845
|
+
assert_nothing_raised { @dummy.avatar = @file }
|
846
|
+
end
|
847
|
+
|
848
|
+
should "return the right value when sent #avatar_updated_at" do
|
849
|
+
now = Time.now
|
850
|
+
Time.stubs(:now).returns(now)
|
851
|
+
@dummy.avatar = @file
|
852
|
+
assert_equal now.to_i, @dummy.avatar.updated_at
|
853
|
+
end
|
854
|
+
end
|
855
|
+
|
856
|
+
context "and avatar_content_type column" do
|
857
|
+
setup do
|
858
|
+
ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string
|
859
|
+
rebuild_class
|
860
|
+
@dummy = Dummy.new
|
861
|
+
end
|
862
|
+
|
863
|
+
should "not error when assigned an attachment" do
|
864
|
+
assert_nothing_raised { @dummy.avatar = @file }
|
865
|
+
end
|
866
|
+
|
867
|
+
should "return the right value when sent #avatar_content_type" do
|
868
|
+
@dummy.avatar = @file
|
869
|
+
assert_equal "image/png", @dummy.avatar.content_type
|
870
|
+
end
|
871
|
+
end
|
872
|
+
|
873
|
+
context "and avatar_file_size column" do
|
874
|
+
setup do
|
875
|
+
ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer
|
876
|
+
rebuild_class
|
877
|
+
@dummy = Dummy.new
|
878
|
+
end
|
879
|
+
|
880
|
+
should "not error when assigned an attachment" do
|
881
|
+
assert_nothing_raised { @dummy.avatar = @file }
|
882
|
+
end
|
883
|
+
|
884
|
+
should "return the right value when sent #avatar_file_size" do
|
885
|
+
@dummy.avatar = @file
|
886
|
+
assert_equal @file.size, @dummy.avatar.size
|
887
|
+
end
|
888
|
+
|
889
|
+
should "return the right value when saved, reloaded, and sent #avatar_file_size" do
|
890
|
+
@dummy.avatar = @file
|
891
|
+
@dummy.save
|
892
|
+
@dummy = Dummy.find(@dummy.id)
|
893
|
+
assert_equal @file.size, @dummy.avatar.size
|
894
|
+
end
|
895
|
+
end
|
896
|
+
|
897
|
+
context "and avatar_fingerprint column" do
|
898
|
+
setup do
|
899
|
+
ActiveRecord::Base.connection.add_column :dummies, :avatar_fingerprint, :string
|
900
|
+
rebuild_class
|
901
|
+
@dummy = Dummy.new
|
902
|
+
end
|
903
|
+
|
904
|
+
should "not error when assigned an attachment" do
|
905
|
+
assert_nothing_raised { @dummy.avatar = @file }
|
906
|
+
end
|
907
|
+
|
908
|
+
should "return the right value when sent #avatar_fingerprint" do
|
909
|
+
@dummy.avatar = @file
|
910
|
+
assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
|
911
|
+
end
|
912
|
+
|
913
|
+
should "return the right value when saved, reloaded, and sent #avatar_fingerprint" do
|
914
|
+
@dummy.avatar = @file
|
915
|
+
@dummy.save
|
916
|
+
@dummy = Dummy.find(@dummy.id)
|
917
|
+
assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
|
918
|
+
end
|
919
|
+
end
|
920
|
+
end
|
921
|
+
end
|