import os

from django.template import Context, Engine, TemplateDoesNotExist
from django.test import SimpleTestCase

from .utils import ROOT

RECURSIVE = os.path.join(ROOT, 'recursive_templates')


class ExtendsBehaviorTests(SimpleTestCase):

    def test_normal_extend(self):
        engine = Engine(dirs=[os.path.join(RECURSIVE, 'fs')])
        template = engine.get_template('one.html')
        output = template.render(Context({}))
        self.assertEqual(output.strip(), 'three two one')

    def test_extend_recursive(self):
        engine = Engine(dirs=[
            os.path.join(RECURSIVE, 'fs'),
            os.path.join(RECURSIVE, 'fs2'),
            os.path.join(RECURSIVE, 'fs3'),
        ])
        template = engine.get_template('recursive.html')
        output = template.render(Context({}))
        self.assertEqual(output.strip(), 'fs3/recursive fs2/recursive fs/recursive')

    def test_extend_missing(self):
        engine = Engine(dirs=[os.path.join(RECURSIVE, 'fs')])
        template = engine.get_template('extend-missing.html')
        with self.assertRaises(TemplateDoesNotExist) as e:
            template.render(Context({}))

        tried = e.exception.tried
        self.assertEqual(len(tried), 1)
        self.assertEqual(tried[0][0].template_name, 'missing.html')

    def test_recursive_multiple_loaders(self):
        engine = Engine(
            dirs=[os.path.join(RECURSIVE, 'fs')],
            loaders=[(
                'django.template.loaders.locmem.Loader', {
                    'one.html': (
                        '{% extends "one.html" %}{% block content %}{{ block.super }} locmem-one{% endblock %}'
                    ),
                    'two.html': (
                        '{% extends "two.html" %}{% block content %}{{ block.super }} locmem-two{% endblock %}'
                    ),
                    'three.html': (
                        '{% extends "three.html" %}{% block content %}{{ block.super }} locmem-three{% endblock %}'
                    ),
                }
            ), 'django.template.loaders.filesystem.Loader'],
        )
        template = engine.get_template('one.html')
        output = template.render(Context({}))
        self.assertEqual(output.strip(), 'three locmem-three two locmem-two one locmem-one')

    def test_extend_self_error(self):
        """
        Catch if a template extends itself and no other matching
        templates are found.
        """
        engine = Engine(dirs=[os.path.join(RECURSIVE, 'fs')])
        template = engine.get_template('self.html')
        with self.assertRaises(TemplateDoesNotExist) as e:
            template.render(Context({}))
        tried = e.exception.tried
        self.assertEqual(len(tried), 1)
        origin, message = tried[0]
        self.assertEqual(origin.template_name, 'self.html')
        self.assertEqual(message, 'Skipped to avoid recursion')

    def test_extend_cached(self):
        engine = Engine(
            dirs=[
                os.path.join(RECURSIVE, 'fs'),
                os.path.join(RECURSIVE, 'fs2'),
                os.path.join(RECURSIVE, 'fs3'),
            ],
            loaders=[
                ('django.template.loaders.cached.Loader', [
                    'django.template.loaders.filesystem.Loader',
                ]),
            ],
        )
        template = engine.get_template('recursive.html')
        output = template.render(Context({}))
        self.assertEqual(output.strip(), 'fs3/recursive fs2/recursive fs/recursive')

        cache = engine.template_loaders[0].get_template_cache
        self.assertEqual(len(cache), 3)
        expected_path = os.path.join('fs', 'recursive.html')
        self.assertTrue(cache['recursive.html'].origin.name.endswith(expected_path))

        # Render another path that uses the same templates from the cache
        template = engine.get_template('other-recursive.html')
        output = template.render(Context({}))
        self.assertEqual(output.strip(), 'fs3/recursive fs2/recursive fs/recursive')

        # Template objects should not be duplicated.
        self.assertEqual(len(cache), 4)
        expected_path = os.path.join('fs', 'other-recursive.html')
        self.assertTrue(cache['other-recursive.html'].origin.name.endswith(expected_path))

    def test_unique_history_per_loader(self):
        """
        Extending should continue even if two loaders return the same
        name for a template.
        """
        engine = Engine(
            loaders=[
                ['django.template.loaders.locmem.Loader', {
                    'base.html': '{% extends "base.html" %}{% block content %}{{ block.super }} loader1{% endblock %}',
                }],
                ['django.template.loaders.locmem.Loader', {
                    'base.html': '{% block content %}loader2{% endblock %}',
                }],
            ]
        )
        template = engine.get_template('base.html')
        output = template.render(Context({}))
        self.assertEqual(output.strip(), 'loader2 loader1')

    def test_block_override_in_extended_included_template(self):
        """
        ExtendsNode.find_template() initializes history with self.origin
        (#28071).
        """
        engine = Engine(
            loaders=[
                ['django.template.loaders.locmem.Loader', {
                    'base.html': "{% extends 'base.html' %}{% block base %}{{ block.super }}2{% endblock %}",
                    'included.html':
                        "{% extends 'included.html' %}{% block included %}{{ block.super }}B{% endblock %}",
                }],
                ['django.template.loaders.locmem.Loader', {
                    'base.html': "{% block base %}1{% endblock %}{% include 'included.html' %}",
                    'included.html': "{% block included %}A{% endblock %}",
                }],
            ],
        )
        template = engine.get_template('base.html')
        self.assertEqual(template.render(Context({})), '12AB')
