from __future__ import with_statement import os from shutil import rmtree import sys from uuid import uuid4 from django.conf import settings from django.template import Context from django.template.loader import get_template from django.test import TestCase TEST_TEMPLATE = """ {# avast ye mateys #} %(extends_string)s {%% block main %%} %(super_string)s %(test_string)s {%% endblock %%} """ class Tests(TestCase): """ Test that ``overextends`` triggers across multiple project and app templates with the same relative path. To achieve this, we need the same template name to exist in multiple apps, as well as at the project level, so we create some fake apps and a project template. These all used a unique ID to ensure they don't collide with anything in the project. When we're done, we clean up our mess. """ def setUp(self): """ Put the test template into a couple of test apps and the project. """ self.root = os.path.dirname(__import__(settings.ROOT_URLCONF).__file__) sys.path.append(self.root) # Add the test apps to INSTALLED_APPS. self.unique_id = str(uuid4()).replace("-", "") self.test_apps = ["app%s%s" % (i, self.unique_id) for i in range(10)] # Create the app directories with the test template. for test_app in self.test_apps: app_dir = os.path.join(self.root, test_app) os.mkdir(app_dir) app_templates = os.path.join(app_dir, "templates") os.mkdir(app_templates) with open(os.path.join(app_dir, "__init__.py"), "w") as f: f.write("") extends = test_app != self.test_apps[-1] self._create_template(app_templates, test_app, extends) # Add the test template to the project, and store a flag # indicating whether or not the project templates directory # existed, so if it does, we can leave it in place when we # clean everything up. project_templates = os.path.join(self.root, "templates") self.project_templates_exist = os.path.exists(project_templates) if not self.project_templates_exist: os.mkdir(project_templates) self._create_template(project_templates, "project", True) def _create_template(self, template_dir, test_string, extends): """ Creates the test template in the given template directory, with the test string injected that we'll use for the real test. """ with open(os.path.join(template_dir, self.unique_id), "w") as f: template_vars = { "test_string": test_string, "extends_string": "", "super_string": "", } if extends: extends_string = "{%% overextends \"%s\" %%}" % self.unique_id template_vars["extends_string"] = extends_string template_vars["super_string"] = "{{ block.super }}" f.write((TEST_TEMPLATE % template_vars).strip()) def test_overextends(self): """ Ensure the test string appear in the rendered template. """ with self.modify_settings(INSTALLED_APPS={ 'prepend': self.test_apps }): html = get_template(self.unique_id).render(Context()) previous = "" for test_string in ["project"] + self.test_apps: self.assertTrue(test_string in html) if previous: self.assertTrue(html.index(test_string) < html.index(previous)) previous = test_string def tearDown(self): """ Delete all the temp files and directories we created in ``setUp``. """ for test_app in self.test_apps: rmtree(os.path.join(self.root, test_app)) if self.project_templates_exist: os.remove(os.path.join(self.root, "templates", self.unique_id)) else: rmtree(os.path.join(self.root, "templates"))