mirror of
https://github.com/django/django.git
synced 2024-12-23 09:36:06 +00:00
188 lines
6.9 KiB
Python
188 lines
6.9 KiB
Python
import pickle
|
|
import unittest
|
|
|
|
from django.core.exceptions import ValidationError
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
from django.core.validators import validate_image_file_extension
|
|
from django.forms import FileField, FileInput
|
|
from django.test import SimpleTestCase
|
|
|
|
try:
|
|
from PIL import Image # NOQA
|
|
except ImportError:
|
|
HAS_PILLOW = False
|
|
else:
|
|
HAS_PILLOW = True
|
|
|
|
|
|
class FileFieldTest(SimpleTestCase):
|
|
def test_filefield_1(self):
|
|
f = FileField()
|
|
with self.assertRaisesMessage(ValidationError, "'This field is required.'"):
|
|
f.clean("")
|
|
with self.assertRaisesMessage(ValidationError, "'This field is required.'"):
|
|
f.clean("", "")
|
|
self.assertEqual("files/test1.pdf", f.clean("", "files/test1.pdf"))
|
|
with self.assertRaisesMessage(ValidationError, "'This field is required.'"):
|
|
f.clean(None)
|
|
with self.assertRaisesMessage(ValidationError, "'This field is required.'"):
|
|
f.clean(None, "")
|
|
self.assertEqual("files/test2.pdf", f.clean(None, "files/test2.pdf"))
|
|
no_file_msg = "'No file was submitted. Check the encoding type on the form.'"
|
|
file = SimpleUploadedFile(None, b"")
|
|
file._name = ""
|
|
with self.assertRaisesMessage(ValidationError, no_file_msg):
|
|
f.clean(file)
|
|
with self.assertRaisesMessage(ValidationError, no_file_msg):
|
|
f.clean(file, "")
|
|
self.assertEqual("files/test3.pdf", f.clean(None, "files/test3.pdf"))
|
|
with self.assertRaisesMessage(ValidationError, no_file_msg):
|
|
f.clean("some content that is not a file")
|
|
with self.assertRaisesMessage(
|
|
ValidationError, "'The submitted file is empty.'"
|
|
):
|
|
f.clean(SimpleUploadedFile("name", None))
|
|
with self.assertRaisesMessage(
|
|
ValidationError, "'The submitted file is empty.'"
|
|
):
|
|
f.clean(SimpleUploadedFile("name", b""))
|
|
self.assertEqual(
|
|
SimpleUploadedFile,
|
|
type(f.clean(SimpleUploadedFile("name", b"Some File Content"))),
|
|
)
|
|
self.assertIsInstance(
|
|
f.clean(
|
|
SimpleUploadedFile(
|
|
"我隻氣墊船裝滿晒鱔.txt",
|
|
"मेरी मँडराने वाली नाव सर्पमीनों से भरी ह".encode(),
|
|
)
|
|
),
|
|
SimpleUploadedFile,
|
|
)
|
|
self.assertIsInstance(
|
|
f.clean(
|
|
SimpleUploadedFile("name", b"Some File Content"), "files/test4.pdf"
|
|
),
|
|
SimpleUploadedFile,
|
|
)
|
|
|
|
def test_filefield_2(self):
|
|
f = FileField(max_length=5)
|
|
with self.assertRaisesMessage(
|
|
ValidationError,
|
|
"'Ensure this filename has at most 5 characters (it has 18).'",
|
|
):
|
|
f.clean(SimpleUploadedFile("test_maxlength.txt", b"hello world"))
|
|
self.assertEqual("files/test1.pdf", f.clean("", "files/test1.pdf"))
|
|
self.assertEqual("files/test2.pdf", f.clean(None, "files/test2.pdf"))
|
|
self.assertIsInstance(
|
|
f.clean(SimpleUploadedFile("name", b"Some File Content")),
|
|
SimpleUploadedFile,
|
|
)
|
|
|
|
def test_filefield_3(self):
|
|
f = FileField(allow_empty_file=True)
|
|
self.assertIsInstance(
|
|
f.clean(SimpleUploadedFile("name", b"")), SimpleUploadedFile
|
|
)
|
|
|
|
def test_filefield_changed(self):
|
|
"""
|
|
The value of data will more than likely come from request.FILES. The
|
|
value of initial data will likely be a filename stored in the database.
|
|
Since its value is of no use to a FileField it is ignored.
|
|
"""
|
|
f = FileField()
|
|
|
|
# No file was uploaded and no initial data.
|
|
self.assertFalse(f.has_changed("", None))
|
|
|
|
# A file was uploaded and no initial data.
|
|
self.assertTrue(
|
|
f.has_changed("", {"filename": "resume.txt", "content": "My resume"})
|
|
)
|
|
|
|
# A file was not uploaded, but there is initial data
|
|
self.assertFalse(f.has_changed("resume.txt", None))
|
|
|
|
# A file was uploaded and there is initial data (file identity is not dealt
|
|
# with here)
|
|
self.assertTrue(
|
|
f.has_changed(
|
|
"resume.txt", {"filename": "resume.txt", "content": "My resume"}
|
|
)
|
|
)
|
|
|
|
def test_disabled_has_changed(self):
|
|
f = FileField(disabled=True)
|
|
self.assertIs(f.has_changed("x", "y"), False)
|
|
|
|
def test_file_picklable(self):
|
|
self.assertIsInstance(pickle.loads(pickle.dumps(FileField())), FileField)
|
|
|
|
|
|
class MultipleFileInput(FileInput):
|
|
allow_multiple_selected = True
|
|
|
|
|
|
class MultipleFileField(FileField):
|
|
def __init__(self, *args, **kwargs):
|
|
kwargs.setdefault("widget", MultipleFileInput())
|
|
super().__init__(*args, **kwargs)
|
|
|
|
def clean(self, data, initial=None):
|
|
single_file_clean = super().clean
|
|
if isinstance(data, (list, tuple)):
|
|
result = [single_file_clean(d, initial) for d in data]
|
|
else:
|
|
result = single_file_clean(data, initial)
|
|
return result
|
|
|
|
|
|
class MultipleFileFieldTest(SimpleTestCase):
|
|
def test_file_multiple(self):
|
|
f = MultipleFileField()
|
|
files = [
|
|
SimpleUploadedFile("name1", b"Content 1"),
|
|
SimpleUploadedFile("name2", b"Content 2"),
|
|
]
|
|
self.assertEqual(f.clean(files), files)
|
|
|
|
def test_file_multiple_empty(self):
|
|
f = MultipleFileField()
|
|
files = [
|
|
SimpleUploadedFile("empty", b""),
|
|
SimpleUploadedFile("nonempty", b"Some Content"),
|
|
]
|
|
msg = "'The submitted file is empty.'"
|
|
with self.assertRaisesMessage(ValidationError, msg):
|
|
f.clean(files)
|
|
with self.assertRaisesMessage(ValidationError, msg):
|
|
f.clean(files[::-1])
|
|
|
|
@unittest.skipUnless(HAS_PILLOW, "Pillow not installed")
|
|
def test_file_multiple_validation(self):
|
|
f = MultipleFileField(validators=[validate_image_file_extension])
|
|
|
|
good_files = [
|
|
SimpleUploadedFile("image1.jpg", b"fake JPEG"),
|
|
SimpleUploadedFile("image2.png", b"faux image"),
|
|
SimpleUploadedFile("image3.bmp", b"fraudulent bitmap"),
|
|
]
|
|
self.assertEqual(f.clean(good_files), good_files)
|
|
|
|
evil_files = [
|
|
SimpleUploadedFile("image1.sh", b"#!/bin/bash -c 'echo pwned!'\n"),
|
|
SimpleUploadedFile("image2.png", b"faux image"),
|
|
SimpleUploadedFile("image3.jpg", b"fake JPEG"),
|
|
]
|
|
|
|
evil_rotations = (
|
|
evil_files[i:] + evil_files[:i] # Rotate by i.
|
|
for i in range(len(evil_files))
|
|
)
|
|
msg = "File extension “sh” is not allowed. Allowed extensions are: "
|
|
for rotated_evil_files in evil_rotations:
|
|
with self.assertRaisesMessage(ValidationError, msg):
|
|
f.clean(rotated_evil_files)
|