Turn output_compression plugin into a library
[rails.git] / vendor / plugins / file_column / test / file_column_test.rb
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