# -*- coding: utf-8 -*- from __future__ import absolute_import import os import sys from django.conf import settings from django.template import loader, RequestContext from django.test import TestCase from django.test.client import RequestFactory from django.utils import six from django.utils.encoding import smart_str from wkhtmltopdf.process import CalledProcessError from wkhtmltopdf.utils import (_options_to_args, make_absolute_paths, wkhtmltopdf, render_to_temporary_file, RenderedFile) from wkhtmltopdf.views import PDFResponse, PDFTemplateView, PDFTemplateResponse class UnicodeContentPDFTemplateView(PDFTemplateView): """ PDFTemplateView with the addition of unicode content in his context. Used in unicode content view testing. """ def get_context_data(self, **kwargs): Base = super(UnicodeContentPDFTemplateView, self) context = Base.get_context_data(**kwargs) context['title'] = u'♥' return context class TestUtils(TestCase): def setUp(self): # Clear standard error self._stderr = sys.stderr sys.stderr = open(os.devnull, 'w') self.factory = RequestFactory() def tearDown(self): sys.stderr = self._stderr def test_options_to_args(self): self.assertEqual(_options_to_args(), []) self.assertEqual(_options_to_args(heart=u'♥', verbose=True, file_name='file-name'), ['--file-name', 'file-name', '--heart', u'♥', '--verbose']) def test_wkhtmltopdf(self): """Should run wkhtmltopdf to generate a PDF""" title = 'A test template.' template = loader.get_template('sample.html') temp_file = render_to_temporary_file(template, context={'title': title}) try: # Standard call pdf_output = wkhtmltopdf(pages=[temp_file.name]) self.assertTrue(pdf_output.startswith(b'%PDF'), pdf_output) # Single page pdf_output = wkhtmltopdf(pages=temp_file.name) self.assertTrue(pdf_output.startswith(b'%PDF'), pdf_output) # Unicode pdf_output = wkhtmltopdf(pages=[temp_file.name], title=u'♥') self.assertTrue(pdf_output.startswith(b'%PDF'), pdf_output) # Invalid arguments self.assertRaises(CalledProcessError, wkhtmltopdf, pages=[]) finally: temp_file.close() def test_wkhtmltopdf_with_unicode_content(self): """A wkhtmltopdf call should render unicode content properly""" title = u'♥' template = loader.get_template('unicode.html') temp_file = render_to_temporary_file(template, context={'title': title}) try: pdf_output = wkhtmltopdf(pages=[temp_file.name]) self.assertTrue(pdf_output.startswith(b'%PDF'), pdf_output) finally: temp_file.close() def test_render_to_temporary_file(self): """Should render a template to a temporary file.""" title = 'A test template.' template = loader.get_template('sample.html') temp_file = render_to_temporary_file(template, context={'title': title}) temp_file.seek(0) saved_content = smart_str(temp_file.read()) self.assertTrue(title in saved_content) temp_file.close() def _render_file(self, template, context): """Helper method for testing rendered file deleted/persists tests.""" render = RenderedFile(template=template, context=context) render.temporary_file.seek(0) saved_content = smart_str(render.temporary_file.read()) return (saved_content, render.filename) def test_rendered_file_deleted_on_production(self): """If WKHTMLTOPDF_DEBUG=False, delete rendered file on object close.""" title = 'A test template.' template = loader.get_template('sample.html') debug = getattr(settings, 'WKHTMLTOPDF_DEBUG', settings.DEBUG) saved_content, filename = self._render_file(template=template, context={'title': title}) # First verify temp file was rendered correctly. self.assertTrue(title in saved_content) # Then check if file is deleted when debug=False. self.assertFalse(debug) self.assertFalse(os.path.isfile(filename)) def test_rendered_file_persists_on_debug(self): """If WKHTMLTOPDF_DEBUG=True, the rendered file should persist.""" title = 'A test template.' template = loader.get_template('sample.html') with self.settings(WKHTMLTOPDF_DEBUG=True): debug = getattr(settings, 'WKHTMLTOPDF_DEBUG', settings.DEBUG) saved_content, filename = self._render_file(template=template, context={'title': title}) # First verify temp file was rendered correctly. self.assertTrue(title in saved_content) # Then check if file persists when debug=True. self.assertTrue(debug) self.assertTrue(os.path.isfile(filename)) class TestViews(TestCase): template = 'sample.html' footer_template = 'footer.html' pdf_filename = 'output.pdf' attached_fileheader = 'attachment; filename="{0}"' inline_fileheader = 'inline; filename="{0}"' def test_pdf_response(self): """Should generate correct HttpResponse object and content type.""" # 404 response = PDFResponse(content='', status=404) self.assertEqual(response.status_code, 404) self.assertEqual(response.content, b'') self.assertEqual(response['Content-Type'], 'application/pdf') self.assertFalse(response.has_header('Content-Disposition')) content = b'%PDF-1.4\n%%EOF' # Without filename response = PDFResponse(content=content) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, content) self.assertEqual(response['Content-Type'], 'application/pdf') self.assertFalse(response.has_header('Content-Disposition')) # With filename response = PDFResponse(content=content, filename="nospace.pdf") self.assertEqual(response['Content-Disposition'], 'attachment; filename="nospace.pdf"') response = PDFResponse(content=content, filename="one space.pdf") self.assertEqual(response['Content-Disposition'], 'attachment; filename="one space.pdf"') response = PDFResponse(content=content, filename="4'5\".pdf") self.assertEqual(response['Content-Disposition'], 'attachment; filename="4\'5.pdf"') response = PDFResponse(content=content, filename=u"♥.pdf") try: import unidecode except ImportError: filename = '?.pdf' else: filename = '.pdf' self.assertEqual(response['Content-Disposition'], 'attachment; filename="{0}"'.format(filename)) # Content as a direct output response = PDFResponse(content=content, filename="nospace.pdf", show_content_in_browser=True) self.assertEqual(response['Content-Disposition'], 'inline; filename="nospace.pdf"') response = PDFResponse(content=content, filename="one space.pdf", show_content_in_browser=True) self.assertEqual(response['Content-Disposition'], 'inline; filename="one space.pdf"') response = PDFResponse(content=content, filename="4'5\".pdf", show_content_in_browser=True) self.assertEqual(response['Content-Disposition'], 'inline; filename="4\'5.pdf"') response = PDFResponse(content=content, filename=u"♥.pdf", show_content_in_browser=True) try: import unidecode except ImportError: filename = '?.pdf' else: filename = '.pdf' self.assertEqual(response['Content-Disposition'], 'inline; filename="{0}"'.format(filename)) # Content-Type response = PDFResponse(content=content, content_type='application/x-pdf') self.assertEqual(response['Content-Type'], 'application/x-pdf') def test_pdf_template_response(self, show_content=False): """Test PDFTemplateResponse.""" context = {'title': 'Heading'} request = RequestFactory().get('/') response = PDFTemplateResponse(request=request, template=self.template, context=context, show_content_in_browser=show_content) self.assertEqual(response._request, request) self.assertEqual(response.template_name, self.template) self.assertEqual(response.context_data, context) self.assertEqual(response.filename, None) self.assertEqual(response.header_template, None) self.assertEqual(response.footer_template, None) self.assertEqual(response.cmd_options, {}) self.assertFalse(response.has_header('Content-Disposition')) # Render to temporary file template = loader.get_template(self.template) tempfile = render_to_temporary_file(template, context=context) tempfile.seek(0) html_content = smart_str(tempfile.read()) self.assertTrue(html_content.startswith('')) self.assertTrue('