file_column 0.3.2

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/lib/test_case.rb ADDED
@@ -0,0 +1,124 @@
1
+ require 'test/unit'
2
+
3
+ # Add the methods +upload+, the <tt>setup_file_fixtures</tt> and
4
+ # <tt>teardown_file_fixtures</tt> to the class Test::Unit::TestCase.
5
+ class Test::Unit::TestCase
6
+ # Returns a +Tempfile+ object as it would have been generated on file upload.
7
+ # Use this method to create the parameters when emulating form posts with
8
+ # file fields.
9
+ #
10
+ # === Example:
11
+ #
12
+ # def test_file_column_post
13
+ # entry = { :title => 'foo', :file => upload('/tmp/foo.txt')}
14
+ # post :upload, :entry => entry
15
+ #
16
+ # # ...
17
+ # end
18
+ #
19
+ # === Parameters
20
+ #
21
+ # * <tt>path</tt> The path to the file to upload.
22
+ # * <tt>content_type</tt> The MIME type of the file. If it is <tt>:guess</tt>,
23
+ # the method will try to guess it.
24
+ def upload(path, content_type=:guess, type=:tempfile)
25
+ if content_type == :guess
26
+ case path
27
+ when /\.jpg$/ then content_type = "image/jpeg"
28
+ when /\.png$/ then content_type = "image/png"
29
+ else content_type = nil
30
+ end
31
+ end
32
+ uploaded_file(path, content_type, File.basename(path), type)
33
+ end
34
+
35
+ # Copies the fixture files from "RAILS_ROOT/test/fixtures/file_column" into
36
+ # the temporary storage directory used for testing
37
+ # ("RAILS_ROOT/test/tmp/file_column"). Call this method in your
38
+ # <tt>setup</tt> methods to get the file fixtures (images, for example) into
39
+ # the directory used by file_column in testing.
40
+ #
41
+ # Note that the files and directories in the "fixtures/file_column" directory
42
+ # must have the same structure as you would expect in your "/public" directory
43
+ # after uploading with FileColumn.
44
+ #
45
+ # For example, the directory structure could look like this:
46
+ #
47
+ # test/fixtures/file_column/
48
+ # `-- container
49
+ # |-- first_image
50
+ # | |-- 1
51
+ # | | `-- image1.jpg
52
+ # | `-- tmp
53
+ # `-- second_image
54
+ # |-- 1
55
+ # | `-- image2.jpg
56
+ # `-- tmp
57
+ #
58
+ # Your fixture file for this one "container" class fixture could look like this:
59
+ #
60
+ # first:
61
+ # id: 1
62
+ # first_image: image1.jpg
63
+ # second_image: image1.jpg
64
+ #
65
+ # A usage example:
66
+ #
67
+ # def setup
68
+ # setup_fixture_files
69
+ #
70
+ # # ...
71
+ # end
72
+ def setup_fixture_files
73
+ tmp_path = File.join(RAILS_ROOT, "test", "tmp", "file_column")
74
+ file_fixtures = Dir.glob File.join(RAILS_ROOT, "test", "fixtures", "file_column", "*")
75
+
76
+ FileUtils.mkdir_p tmp_path unless File.exists?(tmp_path)
77
+ FileUtils.cp_r file_fixtures, tmp_path
78
+ end
79
+
80
+ # Removes the directory "RAILS_ROOT/test/tmp/file_column/" so the files
81
+ # copied on test startup are removed. Call this in your unit test's +teardown+
82
+ # method.
83
+ #
84
+ # A usage example:
85
+ #
86
+ # def teardown
87
+ # teardown_fixture_files
88
+ #
89
+ # # ...
90
+ # end
91
+ def teardown_fixture_files
92
+ FileUtils.rm_rf File.join(RAILS_ROOT, "test", "tmp", "file_column")
93
+ end
94
+
95
+ private
96
+
97
+ def uploaded_file(path, content_type, filename, type=:tempfile) # :nodoc:
98
+ if type == :tempfile
99
+ t = Tempfile.new(File.basename(filename))
100
+ FileUtils.copy_file(path, t.path)
101
+ else
102
+ if path
103
+ t = StringIO.new(IO.read(path))
104
+ else
105
+ t = StringIO.new
106
+ end
107
+ end
108
+ (class << t; self; end).class_eval do
109
+ alias local_path path if type == :tempfile
110
+ define_method(:local_path) { "" } if type == :stringio
111
+ define_method(:original_filename) {filename}
112
+ define_method(:content_type) {content_type}
113
+ end
114
+ return t
115
+ end
116
+ end
117
+
118
+ # If we are running in the "test" environment, we overwrite the default
119
+ # settings for FileColumn so that files are not uploaded into "/public/"
120
+ # in tests but rather into the directory "/test/tmp/file_column".
121
+ if RAILS_ENV == "test"
122
+ FileColumn::ClassMethods::DEFAULT_OPTIONS[:root_path] =
123
+ File.join(RAILS_ROOT, "test", "tmp", "file_column")
124
+ end
@@ -0,0 +1,112 @@
1
+ module FileColumn
2
+ module Validations #:nodoc:
3
+
4
+ def self.append_features(base)
5
+ super
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ # This module contains methods to create validations of uploaded files. All methods
10
+ # in this module will be included as class methods into <tt>ActiveRecord::Base</tt>
11
+ # so that you can use them in your models like this:
12
+ #
13
+ # class Entry < ActiveRecord::Base
14
+ # file_column :image
15
+ # validates_filesize_of :image, :in => 0..1.megabyte
16
+ # end
17
+ module ClassMethods
18
+ EXT_REGEXP = /\.([A-z0-9]+)$/
19
+
20
+ # This validates the file type of one or more file_columns. A list of file columns
21
+ # should be given followed by an options hash.
22
+ #
23
+ # Required options:
24
+ # * <tt>:in</tt> => list of extensions or mime types. If mime types are used they
25
+ # will be mapped into an extension via FileColumn::ClassMethods::MIME_EXTENSIONS.
26
+ #
27
+ # Examples:
28
+ # validates_file_format_of :field, :in => ["gif", "png", "jpg"]
29
+ # validates_file_format_of :field, :in => ["image/jpeg"]
30
+ def validates_file_format_of(*attrs)
31
+
32
+ options = attrs.pop if attrs.last.is_a?Hash
33
+ raise ArgumentError, "Please include the :in option." if !options || !options[:in]
34
+ options[:in] = [options[:in]] if options[:in].is_a?String
35
+ raise ArgumentError, "Invalid value for option :in" unless options[:in].is_a?Array
36
+
37
+ validates_each(attrs, options) do |record, attr, value|
38
+ unless value.blank?
39
+ mime_extensions = record.send("#{attr}_options")[:mime_extensions]
40
+ extensions = options[:in].map{|o| mime_extensions[o] || o }
41
+ record.errors.add attr, "is not a valid format." unless extensions.include?(value.scan(EXT_REGEXP).flatten.first)
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ # This validates the file size of one or more file_columns. A list of file columns
48
+ # should be given followed by an options hash.
49
+ #
50
+ # Required options:
51
+ # * <tt>:in</tt> => A size range. Note that you can use ActiveSupport's
52
+ # numeric extensions for kilobytes, etc.
53
+ #
54
+ # Examples:
55
+ # validates_filesize_of :field, :in => 0..100.megabytes
56
+ # validates_filesize_of :field, :in => 15.kilobytes..1.megabyte
57
+ def validates_filesize_of(*attrs)
58
+
59
+ options = attrs.pop if attrs.last.is_a?Hash
60
+ raise ArgumentError, "Please include the :in option." if !options || !options[:in]
61
+ raise ArgumentError, "Invalid value for option :in" unless options[:in].is_a?Range
62
+
63
+ validates_each(attrs, options) do |record, attr, value|
64
+ unless value.blank?
65
+ size = File.size(value)
66
+ record.errors.add attr, "is smaller than the allowed size range." if size < options[:in].first
67
+ record.errors.add attr, "is larger than the allowed size range." if size > options[:in].last
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ IMAGE_SIZE_REGEXP = /^(\d+)x(\d+)$/
74
+
75
+ # Validates the image size of one or more file_columns. A list of file columns
76
+ # should be given followed by an options hash. The validation will pass
77
+ # if both image dimensions (rows and columns) are at least as big as
78
+ # given in the <tt>:min</tt> option.
79
+ #
80
+ # Required options:
81
+ # * <tt>:min</tt> => minimum image dimension string, in the format NNxNN
82
+ # (columns x rows).
83
+ #
84
+ # Example:
85
+ # validates_image_size :field, :min => "1200x1800"
86
+ #
87
+ # This validation requires RMagick to be installed on your system
88
+ # to check the image's size.
89
+ def validates_image_size(*attrs)
90
+ options = attrs.pop if attrs.last.is_a?Hash
91
+ raise ArgumentError, "Please include a :min option." if !options || !options[:min]
92
+ minimums = options[:min].scan(IMAGE_SIZE_REGEXP).first.collect{|n| n.to_i} rescue []
93
+ raise ArgumentError, "Invalid value for option :min (should be 'XXxYY')" unless minimums.size == 2
94
+
95
+ require 'RMagick'
96
+
97
+ validates_each(attrs, options) do |record, attr, value|
98
+ unless value.blank?
99
+ begin
100
+ img = ::Magick::Image::read(value).first
101
+ record.errors.add('image', "is too small, must be at least #{minimums[0]}x#{minimums[1]}") if ( img.rows < minimums[1] || img.columns < minimums[0] )
102
+ rescue ::Magick::ImageMagickError
103
+ record.errors.add('image', "invalid image")
104
+ end
105
+ img = nil
106
+ GC.start
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,63 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'active_support'
4
+ require 'active_record'
5
+ require 'action_view'
6
+ require File.dirname(__FILE__) + '/connection'
7
+ require 'stringio'
8
+
9
+ RAILS_ROOT = File.dirname(__FILE__)
10
+ RAILS_ENV = ""
11
+
12
+ $: << "../lib"
13
+
14
+ require 'file_column'
15
+ require 'file_compat'
16
+ require 'validations'
17
+ require 'test_case'
18
+
19
+ # do not use the file executable normally in our tests as
20
+ # it may not be present on the machine we are running on
21
+ FileColumn::ClassMethods::DEFAULT_OPTIONS =
22
+ FileColumn::ClassMethods::DEFAULT_OPTIONS.merge({:file_exec => nil})
23
+
24
+ class ActiveRecord::Base
25
+ include FileColumn
26
+ include FileColumn::Validations
27
+ end
28
+
29
+
30
+ class RequestMock
31
+ attr_accessor :relative_url_root
32
+
33
+ def initialize
34
+ @relative_url_root = ""
35
+ end
36
+ end
37
+
38
+ class Test::Unit::TestCase
39
+
40
+ def assert_equal_paths(expected_path, path)
41
+ assert_equal normalize_path(expected_path), normalize_path(path)
42
+ end
43
+
44
+
45
+ private
46
+
47
+ def normalize_path(path)
48
+ Pathname.new(path).realpath
49
+ end
50
+
51
+ def clear_validations
52
+ [:validate, :validate_on_create, :validate_on_update].each do |attr|
53
+ Entry.write_inheritable_attribute attr, []
54
+ Movie.write_inheritable_attribute attr, []
55
+ end
56
+ end
57
+
58
+ def file_path(filename)
59
+ File.expand_path("#{File.dirname(__FILE__)}/fixtures/#{filename}")
60
+ end
61
+
62
+ alias_method :f, :file_path
63
+ end
@@ -0,0 +1,17 @@
1
+ print "Using native MySQL\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ db = 'file_column_test'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "mysql",
10
+ :host => "localhost",
11
+ :username => "rails",
12
+ :password => "",
13
+ :database => db,
14
+ :socket => "/var/run/mysqld/mysqld.sock"
15
+ )
16
+
17
+ load File.dirname(__FILE__) + "/fixtures/schema.rb"
@@ -0,0 +1,97 @@
1
+ require File.dirname(__FILE__) + '/abstract_unit'
2
+ require File.dirname(__FILE__) + '/fixtures/entry'
3
+
4
+ class UrlForFileColumnTest < Test::Unit::TestCase
5
+ include FileColumnHelper
6
+
7
+ def setup
8
+ Entry.file_column :image
9
+ @request = RequestMock.new
10
+ end
11
+
12
+ def test_url_for_file_column_with_temp_entry
13
+ @e = Entry.new(:image => upload(f("skanthak.png")))
14
+ url = url_for_file_column("e", "image")
15
+ assert_match %r{^/entry/image/tmp/\d+(\.\d+)+/skanthak.png$}, url
16
+ end
17
+
18
+ def test_url_for_file_column_with_saved_entry
19
+ @e = Entry.new(:image => upload(f("skanthak.png")))
20
+ assert @e.save
21
+
22
+ url = url_for_file_column("e", "image")
23
+ assert_equal "/entry/image/#{@e.id}/skanthak.png", url
24
+ end
25
+
26
+ def test_url_for_file_column_works_with_symbol
27
+ @e = Entry.new(:image => upload(f("skanthak.png")))
28
+ assert @e.save
29
+
30
+ url = url_for_file_column(:e, :image)
31
+ assert_equal "/entry/image/#{@e.id}/skanthak.png", url
32
+ end
33
+
34
+ def test_url_for_file_column_works_with_object
35
+ e = Entry.new(:image => upload(f("skanthak.png")))
36
+ assert e.save
37
+
38
+ url = url_for_file_column(e, "image")
39
+ assert_equal "/entry/image/#{e.id}/skanthak.png", url
40
+ end
41
+
42
+ def test_url_for_file_column_should_return_nil_on_no_uploaded_file
43
+ e = Entry.new
44
+ assert_nil url_for_file_column(e, "image")
45
+ end
46
+
47
+ def test_url_for_file_column_without_extension
48
+ e = Entry.new
49
+ e.image = uploaded_file(file_path("kerb.jpg"), "something/unknown", "local_filename")
50
+ assert e.save
51
+ assert_equal "/entry/image/#{e.id}/local_filename", url_for_file_column(e, "image")
52
+ end
53
+ end
54
+
55
+ class UrlForFileColumnTest < Test::Unit::TestCase
56
+ include FileColumnHelper
57
+ include ActionView::Helpers::AssetTagHelper
58
+ include ActionView::Helpers::TagHelper
59
+ include ActionView::Helpers::UrlHelper
60
+
61
+ def setup
62
+ Entry.file_column :image
63
+
64
+ # mock up some request data structures for AssetTagHelper
65
+ @request = RequestMock.new
66
+ @request.relative_url_root = "/foo/bar"
67
+ @controller = self
68
+ end
69
+
70
+ def request
71
+ @request
72
+ end
73
+
74
+ IMAGE_URL = %r{^/foo/bar/entry/image/.+/skanthak.png$}
75
+ def test_with_image_tag
76
+ e = Entry.new(:image => upload(f("skanthak.png")))
77
+ html = image_tag url_for_file_column(e, "image")
78
+ url = html.scan(/src=\"(.+)\"/).first.first
79
+
80
+ assert_match IMAGE_URL, url
81
+ end
82
+
83
+ def test_with_link_to_tag
84
+ e = Entry.new(:image => upload(f("skanthak.png")))
85
+ html = link_to "Download", url_for_file_column(e, "image", :absolute => true)
86
+ url = html.scan(/href=\"(.+)\"/).first.first
87
+
88
+ assert_match IMAGE_URL, url
89
+ end
90
+
91
+ def test_relative_url_root_not_modified
92
+ e = Entry.new(:image => upload(f("skanthak.png")))
93
+ url_for_file_column(e, "image", :absolute => true)
94
+
95
+ assert_equal "/foo/bar", @request.relative_url_root
96
+ end
97
+ end
@@ -0,0 +1,650 @@
1
+ require File.dirname(__FILE__) + '/abstract_unit'
2
+
3
+ require File.dirname(__FILE__) + '/fixtures/entry'
4
+
5
+ class Movie < ActiveRecord::Base
6
+ end
7
+
8
+
9
+ class FileColumnTest < Test::Unit::TestCase
10
+
11
+ def setup
12
+ # we define the file_columns here so that we can change
13
+ # settings easily in a single test
14
+
15
+ Entry.file_column :image
16
+ Entry.file_column :file
17
+ Movie.file_column :movie
18
+
19
+ clear_validations
20
+ end
21
+
22
+ def teardown
23
+ FileUtils.rm_rf File.dirname(__FILE__)+"/public/entry/"
24
+ FileUtils.rm_rf File.dirname(__FILE__)+"/public/movie/"
25
+ FileUtils.rm_rf File.dirname(__FILE__)+"/public/my_store_dir/"
26
+ end
27
+
28
+ def test_column_write_method
29
+ assert Entry.new.respond_to?("image=")
30
+ end
31
+
32
+ def test_column_read_method
33
+ assert Entry.new.respond_to?("image")
34
+ end
35
+
36
+ def test_sanitize_filename
37
+ assert_equal "test.jpg", FileColumn::sanitize_filename("test.jpg")
38
+ assert FileColumn::sanitize_filename("../../very_tricky/foo.bar") !~ /[\\\/]/, "slashes not removed"
39
+ assert_equal "__foo", FileColumn::sanitize_filename('`*foo')
40
+ assert_equal "foo.txt", FileColumn::sanitize_filename('c:\temp\foo.txt')
41
+ assert_equal "_.", FileColumn::sanitize_filename(".")
42
+ end
43
+
44
+ def test_default_options
45
+ e = Entry.new
46
+ assert_match %r{/public/entry/image}, e.image_options[:store_dir]
47
+ assert_match %r{/public/entry/image/tmp}, e.image_options[:tmp_base_dir]
48
+ end
49
+
50
+ def test_assign_without_save_with_tempfile
51
+ do_test_assign_without_save(:tempfile)
52
+ end
53
+
54
+ def test_assign_without_save_with_stringio
55
+ do_test_assign_without_save(:stringio)
56
+ end
57
+
58
+ def do_test_assign_without_save(upload_type)
59
+ e = Entry.new
60
+ e.image = uploaded_file(file_path("skanthak.png"), "image/png", "skanthak.png", upload_type)
61
+ assert e.image.is_a?(String), "#{e.image.inspect} is not a String"
62
+ assert File.exists?(e.image)
63
+ assert FileUtils.identical?(e.image, file_path("skanthak.png"))
64
+ end
65
+
66
+ def test_filename_preserved
67
+ e = Entry.new
68
+ e.image = uploaded_file(file_path("kerb.jpg"), "image/jpeg", "local_filename.jpg")
69
+ assert_equal "local_filename.jpg", File.basename(e.image)
70
+ end
71
+
72
+ def test_filename_stored_in_attribute
73
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg"))
74
+ assert_equal "kerb.jpg", e["image"]
75
+ end
76
+
77
+ def test_extension_added
78
+ e = Entry.new
79
+ e.image = uploaded_file(file_path("kerb.jpg"), "image/jpeg", "local_filename")
80
+ assert_equal "local_filename.jpg", File.basename(e.image)
81
+ assert_equal "local_filename.jpg", e["image"]
82
+ end
83
+
84
+ def test_no_extension_without_content_type
85
+ e = Entry.new
86
+ e.image = uploaded_file(file_path("kerb.jpg"), "something/unknown", "local_filename")
87
+ assert_equal "local_filename", File.basename(e.image)
88
+ assert_equal "local_filename", e["image"]
89
+ end
90
+
91
+ def test_extension_unknown_type
92
+ e = Entry.new
93
+ e.image = uploaded_file(file_path("kerb.jpg"), "not/known", "local_filename")
94
+ assert_equal "local_filename", File.basename(e.image)
95
+ assert_equal "local_filename", e["image"]
96
+ end
97
+
98
+ def test_extension_unknown_type_with_extension
99
+ e = Entry.new
100
+ e.image = uploaded_file(file_path("kerb.jpg"), "not/known", "local_filename.abc")
101
+ assert_equal "local_filename.abc", File.basename(e.image)
102
+ assert_equal "local_filename.abc", e["image"]
103
+ end
104
+
105
+ def test_extension_corrected
106
+ e = Entry.new
107
+ e.image = uploaded_file(file_path("kerb.jpg"), "image/jpeg", "local_filename.jpeg")
108
+ assert_equal "local_filename.jpg", File.basename(e.image)
109
+ assert_equal "local_filename.jpg", e["image"]
110
+ end
111
+
112
+ def test_double_extension
113
+ e = Entry.new
114
+ e.image = uploaded_file(file_path("kerb.jpg"), "application/x-tgz", "local_filename.tar.gz")
115
+ assert_equal "local_filename.tar.gz", File.basename(e.image)
116
+ assert_equal "local_filename.tar.gz", e["image"]
117
+ end
118
+
119
+ FILE_UTILITY = "/usr/bin/file"
120
+
121
+ def test_get_content_type_with_file
122
+ Entry.file_column :image, :file_exec => FILE_UTILITY
123
+
124
+ # run this test only if the machine we are running on
125
+ # has the file utility installed
126
+ if File.executable?(FILE_UTILITY)
127
+ e = Entry.new
128
+ file = FileColumn::TempUploadedFile.new(e, "image")
129
+ file.instance_variable_set :@dir, File.dirname(file_path("kerb.jpg"))
130
+ file.instance_variable_set :@filename, File.basename(file_path("kerb.jpg"))
131
+
132
+ assert_equal "image/jpeg", file.get_content_type
133
+ else
134
+ puts "Warning: Skipping test_get_content_type_with_file test as '#{options[:file_exec]}' does not exist"
135
+ end
136
+ end
137
+
138
+ def test_fix_extension_with_file
139
+ Entry.file_column :image, :file_exec => FILE_UTILITY
140
+
141
+ # run this test only if the machine we are running on
142
+ # has the file utility installed
143
+ if File.executable?(FILE_UTILITY)
144
+ e = Entry.new(:image => uploaded_file(file_path("skanthak.png"), "", "skanthak.jpg"))
145
+
146
+ assert_equal "skanthak.png", File.basename(e.image)
147
+ else
148
+ puts "Warning: Skipping test_fix_extension_with_file test as '#{options[:file_exec]}' does not exist"
149
+ end
150
+ end
151
+
152
+ def test_do_not_fix_file_extensions
153
+ Entry.file_column :image, :fix_file_extensions => false
154
+
155
+ e = Entry.new(:image => uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb"))
156
+
157
+ assert_equal "kerb", File.basename(e.image)
158
+ end
159
+
160
+ def test_correct_extension
161
+ e = Entry.new
162
+ file = FileColumn::TempUploadedFile.new(e, "image")
163
+
164
+ assert_equal "filename.jpg", file.correct_extension("filename.jpeg","jpg")
165
+ assert_equal "filename.tar.gz", file.correct_extension("filename.jpg","tar.gz")
166
+ assert_equal "filename.jpg", file.correct_extension("filename.tar.gz","jpg")
167
+ assert_equal "Protokoll_01.09.2005.doc", file.correct_extension("Protokoll_01.09.2005","doc")
168
+ assert_equal "strange.filenames.exist.jpg", file.correct_extension("strange.filenames.exist","jpg")
169
+ assert_equal "another.strange.one.jpg", file.correct_extension("another.strange.one.png","jpg")
170
+ end
171
+
172
+ def test_assign_with_save
173
+ e = Entry.new
174
+ e.image = uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg")
175
+ tmp_file_path = e.image
176
+ assert e.save
177
+ assert File.exists?(e.image)
178
+ assert FileUtils.identical?(e.image, file_path("kerb.jpg"))
179
+ assert_equal "#{e.id}/kerb.jpg", e.image_relative_path
180
+ assert !File.exists?(tmp_file_path), "temporary file '#{tmp_file_path}' not removed"
181
+ assert !File.exists?(File.dirname(tmp_file_path)), "temporary directory '#{File.dirname(tmp_file_path)}' not removed"
182
+
183
+ local_path = e.image
184
+ e = Entry.find(e.id)
185
+ assert_equal local_path, e.image
186
+ end
187
+
188
+ def test_dir_methods
189
+ e = Entry.new
190
+ e.image = uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg")
191
+ e.save
192
+
193
+ assert_equal_paths File.join(RAILS_ROOT, "public", "entry", "image", e.id.to_s), e.image_dir
194
+ assert_equal File.join(e.id.to_s), e.image_relative_dir
195
+ end
196
+
197
+ def test_store_dir_callback
198
+ Entry.file_column :image, {:store_dir => :my_store_dir}
199
+ e = Entry.new
200
+
201
+ e.image = uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg")
202
+ assert e.save
203
+
204
+ assert_equal_paths File.join(RAILS_ROOT, "public", "my_store_dir", e.id), e.image_dir
205
+ end
206
+
207
+ def test_tmp_dir_with_store_dir_callback
208
+ Entry.file_column :image, {:store_dir => :my_store_dir}
209
+ e = Entry.new
210
+ e.image = upload(f("kerb.jpg"))
211
+
212
+ assert_equal File.expand_path(File.join(RAILS_ROOT, "public", "my_store_dir", "tmp")), File.expand_path(File.join(e.image_dir,".."))
213
+ end
214
+
215
+ def test_invalid_store_dir_callback
216
+ Entry.file_column :image, {:store_dir => :my_store_dir_doesnt_exit}
217
+ e = Entry.new
218
+ assert_raise(ArgumentError) {
219
+ e.image = uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg")
220
+ e.save
221
+ }
222
+ end
223
+
224
+ def test_subdir_parameter
225
+ e = Entry.new
226
+ assert_nil e.image("thumb")
227
+ assert_nil e.image_relative_path("thumb")
228
+ assert_nil e.image(nil)
229
+
230
+ e.image = uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg")
231
+
232
+ assert_equal "kerb.jpg", File.basename(e.image("thumb"))
233
+ assert_equal "kerb.jpg", File.basename(e.image_relative_path("thumb"))
234
+
235
+ assert_equal File.join(e.image_dir,"thumb","kerb.jpg"), e.image("thumb")
236
+ assert_match %r{/thumb/kerb\.jpg$}, e.image_relative_path("thumb")
237
+
238
+ assert_equal e.image, e.image(nil)
239
+ assert_equal e.image_relative_path, e.image_relative_path(nil)
240
+ end
241
+
242
+ def test_cleanup_after_destroy
243
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg"))
244
+ assert e.save
245
+ local_path = e.image
246
+ assert File.exists?(local_path)
247
+ assert e.destroy
248
+ assert !File.exists?(local_path), "'#{local_path}' still exists although entry was destroyed"
249
+ assert !File.exists?(File.dirname(local_path))
250
+ end
251
+
252
+ def test_keep_tmp_image
253
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg"))
254
+ e.validation_should_fail = true
255
+ assert !e.save, "e should not save due to validation errors"
256
+ assert File.exists?(local_path = e.image)
257
+ image_temp = e.image_temp
258
+ e = Entry.new("image_temp" => image_temp)
259
+ assert_equal local_path, e.image
260
+ assert e.save
261
+ assert FileUtils.identical?(e.image, file_path("kerb.jpg"))
262
+ end
263
+
264
+ def test_keep_tmp_image_with_existing_image
265
+ e = Entry.new("image" =>uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg"))
266
+ assert e.save
267
+ assert File.exists?(local_path = e.image)
268
+ e = Entry.find(e.id)
269
+ e.image = uploaded_file(file_path("skanthak.png"), "image/png", "skanthak.png")
270
+ e.validation_should_fail = true
271
+ assert !e.save
272
+ temp_path = e.image_temp
273
+ e = Entry.find(e.id)
274
+ e.image_temp = temp_path
275
+ assert e.save
276
+
277
+ assert FileUtils.identical?(e.image, file_path("skanthak.png"))
278
+ assert !File.exists?(local_path), "old image has not been deleted"
279
+ end
280
+
281
+ def test_replace_tmp_image_temp_first
282
+ do_test_replace_tmp_image([:image_temp, :image])
283
+ end
284
+
285
+ def test_replace_tmp_image_temp_last
286
+ do_test_replace_tmp_image([:image, :image_temp])
287
+ end
288
+
289
+ def do_test_replace_tmp_image(order)
290
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg"))
291
+ e.validation_should_fail = true
292
+ assert !e.save
293
+ image_temp = e.image_temp
294
+ temp_path = e.image
295
+ new_img = uploaded_file(file_path("skanthak.png"), "image/png", "skanthak.png")
296
+ e = Entry.new
297
+ for method in order
298
+ case method
299
+ when :image_temp then e.image_temp = image_temp
300
+ when :image then e.image = new_img
301
+ end
302
+ end
303
+ assert e.save
304
+ assert FileUtils.identical?(e.image, file_path("skanthak.png")), "'#{e.image}' is not the expected 'skanthak.png'"
305
+ assert !File.exists?(temp_path), "temporary file '#{temp_path}' is not cleaned up"
306
+ assert !File.exists?(File.dirname(temp_path)), "temporary directory not cleaned up"
307
+ assert e.image_just_uploaded?
308
+ end
309
+
310
+ def test_replace_image_on_saved_object
311
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg"))
312
+ assert e.save
313
+ old_file = e.image
314
+ e = Entry.find(e.id)
315
+ e.image = uploaded_file(file_path("skanthak.png"), "image/png", "skanthak.png")
316
+ assert e.save
317
+ assert FileUtils.identical?(file_path("skanthak.png"), e.image)
318
+ assert old_file != e.image
319
+ assert !File.exists?(old_file), "'#{old_file}' has not been cleaned up"
320
+ end
321
+
322
+ def test_edit_without_touching_image
323
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg"))
324
+ assert e.save
325
+ e = Entry.find(e.id)
326
+ assert e.save
327
+ assert FileUtils.identical?(file_path("kerb.jpg"), e.image)
328
+ end
329
+
330
+ def test_save_without_image
331
+ e = Entry.new
332
+ assert e.save
333
+ e.reload
334
+ assert_nil e.image
335
+ end
336
+
337
+ def test_delete_saved_image
338
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg"))
339
+ assert e.save
340
+ local_path = e.image
341
+ e.image = nil
342
+ assert_nil e.image
343
+ assert File.exists?(local_path), "file '#{local_path}' should not be deleted until transaction is saved"
344
+ assert e.save
345
+ assert_nil e.image
346
+ assert !File.exists?(local_path)
347
+ e.reload
348
+ assert e["image"].blank?
349
+ e = Entry.find(e.id)
350
+ assert_nil e.image
351
+ end
352
+
353
+ def test_delete_tmp_image
354
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg"))
355
+ local_path = e.image
356
+ e.image = nil
357
+ assert_nil e.image
358
+ assert e["image"].blank?
359
+ assert !File.exists?(local_path)
360
+ end
361
+
362
+ def test_delete_nonexistant_image
363
+ e = Entry.new
364
+ e.image = nil
365
+ assert e.save
366
+ assert_nil e.image
367
+ end
368
+
369
+ def test_delete_image_on_non_null_column
370
+ e = Entry.new("file" => upload(f("skanthak.png")))
371
+ assert e.save
372
+
373
+ local_path = e.file
374
+ assert File.exists?(local_path)
375
+ e.file = nil
376
+ assert e.save
377
+ assert !File.exists?(local_path)
378
+ end
379
+
380
+ def test_ie_filename
381
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", 'c:\images\kerb.jpg'))
382
+ assert e.image_relative_path =~ /^tmp\/[\d\.]+\/kerb\.jpg$/, "relative path '#{e.image_relative_path}' was not as expected"
383
+ assert File.exists?(e.image)
384
+ end
385
+
386
+ def test_just_uploaded?
387
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", 'c:\images\kerb.jpg'))
388
+ assert e.image_just_uploaded?
389
+ assert e.save
390
+ assert e.image_just_uploaded?
391
+
392
+ e = Entry.new("image" => uploaded_file(file_path("kerb.jpg"), "image/jpeg", 'kerb.jpg'))
393
+ temp_path = e.image_temp
394
+ e = Entry.new("image_temp" => temp_path)
395
+ assert !e.image_just_uploaded?
396
+ assert e.save
397
+ assert !e.image_just_uploaded?
398
+ end
399
+
400
+ def test_empty_tmp
401
+ e = Entry.new
402
+ e.image_temp = ""
403
+ assert_nil e.image
404
+ end
405
+
406
+ def test_empty_tmp_with_image
407
+ e = Entry.new
408
+ e.image_temp = ""
409
+ e.image = uploaded_file(file_path("kerb.jpg"), "image/jpeg", 'c:\images\kerb.jpg')
410
+ local_path = e.image
411
+ assert File.exists?(local_path)
412
+ e.image_temp = ""
413
+ assert local_path, e.image
414
+ end
415
+
416
+ def test_empty_filename
417
+ e = Entry.new
418
+ assert_equal "", e["file"]
419
+ assert_nil e.file
420
+ assert_nil e["image"]
421
+ assert_nil e.image
422
+ end
423
+
424
+ def test_with_two_file_columns
425
+ e = Entry.new
426
+ e.image = uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg")
427
+ e.file = uploaded_file(file_path("skanthak.png"), "image/png", "skanthak.png")
428
+ assert e.save
429
+ assert_match %{/entry/image/}, e.image
430
+ assert_match %{/entry/file/}, e.file
431
+ assert FileUtils.identical?(e.image, file_path("kerb.jpg"))
432
+ assert FileUtils.identical?(e.file, file_path("skanthak.png"))
433
+ end
434
+
435
+ def test_with_two_models
436
+ e = Entry.new(:image => uploaded_file(file_path("kerb.jpg"), "image/jpeg", "kerb.jpg"))
437
+ m = Movie.new(:movie => uploaded_file(file_path("skanthak.png"), "image/png", "skanthak.png"))
438
+ assert e.save
439
+ assert m.save
440
+ assert_match %{/entry/image/}, e.image
441
+ assert_match %{/movie/movie/}, m.movie
442
+ assert FileUtils.identical?(e.image, file_path("kerb.jpg"))
443
+ assert FileUtils.identical?(m.movie, file_path("skanthak.png"))
444
+ end
445
+
446
+ def test_no_file_uploaded
447
+ e = Entry.new
448
+ assert_nothing_raised { e.image =
449
+ uploaded_file(nil, "application/octet-stream", "", :stringio) }
450
+ assert_equal nil, e.image
451
+ end
452
+
453
+ # when safari submits a form where no file has been
454
+ # selected, it does not transmit a content-type and
455
+ # the result is an empty string ""
456
+ def test_no_file_uploaded_with_safari
457
+ e = Entry.new
458
+ assert_nothing_raised { e.image = "" }
459
+ assert_equal nil, e.image
460
+ end
461
+
462
+ def test_detect_wrong_encoding
463
+ e = Entry.new
464
+ assert_raise(TypeError) { e.image ="img42.jpg" }
465
+ end
466
+
467
+ def test_serializable_before_save
468
+ e = Entry.new
469
+ e.image = uploaded_file(file_path("skanthak.png"), "image/png", "skanthak.png")
470
+ assert_nothing_raised {
471
+ flash = Marshal.dump(e)
472
+ e = Marshal.load(flash)
473
+ }
474
+ assert File.exists?(e.image)
475
+ end
476
+
477
+ def test_should_call_after_upload_on_new_upload
478
+ Entry.file_column :image, :after_upload => [:after_assign]
479
+ e = Entry.new
480
+ e.image = upload(f("skanthak.png"))
481
+ assert e.after_assign_called?
482
+ end
483
+
484
+ def test_should_call_user_after_save_on_save
485
+ e = Entry.new(:image => upload(f("skanthak.png")))
486
+ assert e.save
487
+
488
+ assert_kind_of FileColumn::PermanentUploadedFile, e.send(:image_state)
489
+ assert e.after_save_called?
490
+ end
491
+
492
+
493
+ def test_assign_standard_files
494
+ e = Entry.new
495
+ e.image = File.new(file_path('skanthak.png'))
496
+
497
+ assert_equal 'skanthak.png', File.basename(e.image)
498
+ assert FileUtils.identical?(file_path('skanthak.png'), e.image)
499
+
500
+ assert e.save
501
+ end
502
+
503
+
504
+ def test_validates_filesize
505
+ Entry.validates_filesize_of :image, :in => 50.kilobytes..100.kilobytes
506
+
507
+ e = Entry.new(:image => upload(f("kerb.jpg")))
508
+ assert e.save
509
+
510
+ e.image = upload(f("skanthak.png"))
511
+ assert !e.save
512
+ assert e.errors.invalid?("image")
513
+ end
514
+
515
+ def test_validates_file_format_simple
516
+ e = Entry.new(:image => upload(f("skanthak.png")))
517
+ assert e.save
518
+
519
+ Entry.validates_file_format_of :image, :in => ["jpg"]
520
+
521
+ e.image = upload(f("kerb.jpg"))
522
+ assert e.save
523
+
524
+ e.image = upload(f("mysql.sql"))
525
+ assert !e.save
526
+ assert e.errors.invalid?("image")
527
+
528
+ end
529
+
530
+ def test_validates_image_size
531
+ Entry.validates_image_size :image, :min => "640x480"
532
+
533
+ e = Entry.new(:image => upload(f("kerb.jpg")))
534
+ assert e.save
535
+
536
+ e = Entry.new(:image => upload(f("skanthak.png")))
537
+ assert !e.save
538
+ assert e.errors.invalid?("image")
539
+ end
540
+
541
+ def do_permission_test(uploaded_file, permissions=0641)
542
+ Entry.file_column :image, :permissions => permissions
543
+
544
+ e = Entry.new(:image => uploaded_file)
545
+ assert e.save
546
+
547
+ assert_equal permissions, (File.stat(e.image).mode & 0777)
548
+ end
549
+
550
+ def test_permissions_with_small_file
551
+ do_permission_test upload(f("skanthak.png"), :guess, :stringio)
552
+ end
553
+
554
+ def test_permission_with_big_file
555
+ do_permission_test upload(f("kerb.jpg"))
556
+ end
557
+
558
+ def test_permission_that_overrides_umask
559
+ do_permission_test upload(f("skanthak.png"), :guess, :stringio), 0666
560
+ do_permission_test upload(f("kerb.jpg")), 0666
561
+ end
562
+
563
+ def test_access_with_empty_id
564
+ # an empty id might happen after a clone or through some other
565
+ # strange event. Since we would create a path that contains nothing
566
+ # where the id would have been, we should fail fast with an exception
567
+ # in this case
568
+
569
+ e = Entry.new(:image => upload(f("skanthak.png")))
570
+ assert e.save
571
+ id = e.id
572
+
573
+ e = Entry.find(id)
574
+
575
+ e["id"] = ""
576
+ assert_raise(RuntimeError) { e.image }
577
+
578
+ e = Entry.find(id)
579
+ e["id"] = nil
580
+ assert_raise(RuntimeError) { e.image }
581
+ end
582
+ end
583
+
584
+ # Tests for moving temp dir to permanent dir
585
+ class FileColumnMoveTest < Test::Unit::TestCase
586
+
587
+ def setup
588
+ # we define the file_columns here so that we can change
589
+ # settings easily in a single test
590
+
591
+ Entry.file_column :image
592
+
593
+ end
594
+
595
+ def teardown
596
+ FileUtils.rm_rf File.dirname(__FILE__)+"/public/entry/"
597
+ end
598
+
599
+ def test_should_move_additional_files_from_tmp
600
+ e = Entry.new
601
+ e.image = uploaded_file(file_path("skanthak.png"), "image/png", "skanthak.png")
602
+ FileUtils.cp file_path("kerb.jpg"), File.dirname(e.image)
603
+ assert e.save
604
+ dir = File.dirname(e.image)
605
+ assert File.exists?(File.join(dir, "skanthak.png"))
606
+ assert File.exists?(File.join(dir, "kerb.jpg"))
607
+ end
608
+
609
+ def test_should_move_direcotries_on_save
610
+ e = Entry.new(:image => upload(f("skanthak.png")))
611
+
612
+ FileUtils.mkdir( e.image_dir+"/foo" )
613
+ FileUtils.cp file_path("kerb.jpg"), e.image_dir+"/foo/kerb.jpg"
614
+
615
+ assert e.save
616
+
617
+ assert File.exists?(e.image)
618
+ assert File.exists?(File.dirname(e.image)+"/foo/kerb.jpg")
619
+ end
620
+
621
+ def test_should_overwrite_dirs_with_files_on_reupload
622
+ e = Entry.new(:image => upload(f("skanthak.png")))
623
+
624
+ FileUtils.mkdir( e.image_dir+"/kerb.jpg")
625
+ FileUtils.cp file_path("kerb.jpg"), e.image_dir+"/kerb.jpg/"
626
+ assert e.save
627
+
628
+ e.image = upload(f("kerb.jpg"))
629
+ assert e.save
630
+
631
+ assert File.file?(e.image_dir+"/kerb.jpg")
632
+ end
633
+
634
+ def test_should_overwrite_files_with_dirs_on_reupload
635
+ e = Entry.new(:image => upload(f("skanthak.png")))
636
+
637
+ assert e.save
638
+ assert File.file?(e.image_dir+"/skanthak.png")
639
+
640
+ e.image = upload(f("kerb.jpg"))
641
+ FileUtils.mkdir(e.image_dir+"/skanthak.png")
642
+
643
+ assert e.save
644
+ assert File.file?(e.image_dir+"/kerb.jpg")
645
+ assert !File.file?(e.image_dir+"/skanthak.png")
646
+ assert File.directory?(e.image_dir+"/skanthak.png")
647
+ end
648
+
649
+ end
650
+