Browse Source

Fixed #23911 -- Added support for buffer file uploads in the test client

Thomas Tanner 10 years ago
parent
commit
018d110ef5
5 changed files with 47 additions and 4 deletions
  1. 1 0
      AUTHORS
  2. 8 3
      django/test/client.py
  3. 2 0
      docs/releases/1.8.txt
  4. 7 0
      docs/topics/testing/tools.txt
  5. 29 1
      tests/file_uploads/tests.py

+ 1 - 0
AUTHORS

@@ -650,6 +650,7 @@ answer newbie questions, and generally made Django that much better:
     Thomas Sorrel
     Thomas Steinacher <http://www.eggdrop.ch/>
     Thomas Stromberg <tstromberg@google.com>
+    Thomas Tanner <tanner@gmx.net>
     tibimicu@gmx.net
     Tim Graham <timograham@gmail.com>
     Tim Heap <tim@timheap.me>

+ 8 - 3
django/test/client.py

@@ -195,20 +195,25 @@ def encode_multipart(boundary, data):
 
 def encode_file(boundary, key, file):
     to_bytes = lambda s: force_bytes(s, settings.DEFAULT_CHARSET)
+    filename = os.path.basename(file.name) if hasattr(file, 'name') else ''
     if hasattr(file, 'content_type'):
         content_type = file.content_type
+    elif filename:
+        content_type = mimetypes.guess_type(filename)[0]
     else:
-        content_type = mimetypes.guess_type(file.name)[0]
+        content_type = None
 
     if content_type is None:
         content_type = 'application/octet-stream'
+    if not filename:
+        filename = key
     return [
         to_bytes('--%s' % boundary),
         to_bytes('Content-Disposition: form-data; name="%s"; filename="%s"'
-                 % (key, os.path.basename(file.name))),
+                 % (key, filename)),
         to_bytes('Content-Type: %s' % content_type),
         b'',
-        file.read()
+        to_bytes(file.read())
     ]
 
 

+ 2 - 0
docs/releases/1.8.txt

@@ -511,6 +511,8 @@ Tests
   :meth:`TestCase.setUpTestData() <django.test.TestCase.setUpTestData>`. Using
   this technique can speed up the tests as compared to using ``setUp()``.
 
+* Added test client support for file uploads with file-like objects.
+
 Validators
 ^^^^^^^^^^
 

+ 7 - 0
docs/topics/testing/tools.txt

@@ -238,6 +238,13 @@ Use the ``django.test.Client`` class to make requests.
         (The name ``attachment`` here is not relevant; use whatever name your
         file-processing code expects.)
 
+        You may also provide any file-like object (e.g., :class:`~io.StringIO` or
+        :class:`~io.BytesIO`) as a file handle.
+
+        .. versionadded:: 1.8
+
+            The ability to use a file-like object was added.
+
         Note that if you wish to use the same file handle for multiple
         ``post()`` calls then you will need to manually reset the file
         pointer between posts. The easiest way to do this is to

+ 29 - 1
tests/file_uploads/tests.py

@@ -17,7 +17,7 @@ from django.test import TestCase, client
 from django.test import override_settings
 from django.utils.encoding import force_bytes
 from django.utils.http import urlquote
-from django.utils.six import StringIO
+from django.utils.six import BytesIO, StringIO
 
 from . import uploadhandler
 from .models import FileModel
@@ -262,6 +262,34 @@ class FileUploadTests(TestCase):
             self.assertLess(len(got), 256,
                             "Got a long file name (%s characters)." % len(got))
 
+    def test_file_content(self):
+        tdir = tempfile.gettempdir()
+
+        file = tempfile.NamedTemporaryFile
+        with file(suffix=".ctype_extra", dir=tdir) as no_content_type, \
+                file(suffix=".ctype_extra", dir=tdir) as simple_file:
+            no_content_type.write(b'no content')
+            no_content_type.seek(0)
+
+            simple_file.write(b'text content')
+            simple_file.seek(0)
+            simple_file.content_type = 'text/plain'
+
+            string_io = StringIO('string content')
+            bytes_io = BytesIO(b'binary content')
+
+            response = self.client.post('/echo_content/', {
+                'no_content_type': no_content_type,
+                'simple_file': simple_file,
+                'string': string_io,
+                'binary': bytes_io,
+            })
+            received = json.loads(response.content.decode('utf-8'))
+            self.assertEqual(received['no_content_type'], 'no content')
+            self.assertEqual(received['simple_file'], 'text content')
+            self.assertEqual(received['string'], 'string content')
+            self.assertEqual(received['binary'], 'binary content')
+
     def test_content_type_extra(self):
         """Uploaded files may have content type parameters available."""
         tdir = tempfile.gettempdir()