summaryrefslogtreecommitdiff
path: root/tests/unit/utils/test_jinja.py
blob: 37f499d7470fe8287a62668508df9fb9098bd6ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# Copyright 2014-2021 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""Tests for qutebrowser.utils.jinja."""

import pathlib
import logging

import jinja2.exceptions
import pytest
from qutebrowser.qt.core import QUrl

from qutebrowser.utils import jinja
from qutebrowser.config import configexc


@pytest.fixture(autouse=True)
def patch_read_file(monkeypatch):
    """pytest fixture to patch resources.read_file."""
    def _read_file(filepath):
        """A read_file which returns a simple template if the path is right."""
        path = pathlib.Path(filepath)
        html_path = pathlib.Path('html')
        if path == html_path / 'test.html':
            return """Hello {{var}}"""
        elif path == html_path / 'test2.html':
            return """{{ resource_url('utils/testfile') }}"""
        elif path == html_path / 'test3.html':
            return """{{ data_url('testfile.txt') }}"""
        elif path == html_path / 'undef.html':
            return """{{ does_not_exist() }}"""
        elif path == html_path / 'attributeerror.html':
            return """{{ obj.foobar }}"""
        else:
            raise OSError(f"Invalid path {filepath}!")

    def _read_file_binary(filepath):
        if filepath == 'testfile.txt':
            return b'foo'
        else:
            raise OSError(f"Invalid path {filepath}!")

    monkeypatch.setattr(jinja.resources, 'read_file', _read_file)
    monkeypatch.setattr(jinja.resources, 'read_file_binary', _read_file_binary)


def test_simple_template():
    """Test with a simple template."""
    data = jinja.render('test.html', var='World')
    assert data == "Hello World"


def test_resource_url():
    """Test resource_url() which can be used from templates."""
    data = jinja.render('test2.html')
    print(data)
    url = QUrl(data)
    assert url.isValid()
    assert url.toDisplayString() == 'qute://resource/utils/testfile'


def test_data_url():
    """Test data_url() which can be used from templates."""
    data = jinja.render('test3.html')
    print(data)
    url = QUrl(data)
    assert url.isValid()
    assert data == 'data:text/plain;base64,Zm9v'  # 'foo'


def test_not_found(caplog):
    """Test with a template which does not exist."""
    with caplog.at_level(logging.ERROR):
        data = jinja.render('does_not_exist.html')
    assert "The does_not_exist.html template could not be found!" in data

    assert caplog.messages[0].startswith("The does_not_exist.html template"
                                         " could not be loaded from")


def test_utf8():
    """Test rendering with a UTF8 template.

    This was an attempt to get a failing test case for #127 but it seems
    the issue is elsewhere.

    https://github.com/qutebrowser/qutebrowser/issues/127
    """
    data = jinja.render('test.html', var='\u2603')
    assert data == "Hello \u2603"


def test_undefined_function(caplog):
    """Make sure undefined attributes crash since we preload resources.."""
    with pytest.raises(jinja2.exceptions.UndefinedError):
        jinja.render('undef.html')


def test_attribute_error():
    """Make sure accessing an unknown attribute fails."""
    with pytest.raises(AttributeError):
        jinja.render('attributeerror.html', obj=object())


@pytest.mark.parametrize('escape', [True, False])
def test_autoescape(escape):
    if not escape:
        with jinja.environment.no_autoescape():
            template = jinja.environment.from_string("{{ v }}")
        assert template.render(v='<foo') == '<foo'

    template = jinja.environment.from_string("{{ v }}")
    assert template.render(v='<foo') == '&lt;foo'


@pytest.mark.parametrize('template, expected', [
    ('{{ func1(conf.aliases) }} {{ func2(conf.backend) }}',
     ['aliases', 'backend']),
    ('{{ conf.aliases["a"].propname }}', ['aliases']),
    ('{{ conf.auto_save.interval + conf.hints.min_chars }}',
     ['auto_save.interval', 'hints.min_chars']),
    ('{{ notconf.a.b.c }}', []),
])
def test_template_config_variables(template, expected, config_stub):
    assert jinja.template_config_variables(template) == frozenset(expected)


@pytest.mark.parametrize('template', [
    '{{ func1(conf.aaa) }}',
    '{{ conf.bbb["a"].propname }}',
    '{{ conf.ccc + 1 }}',
])
def test_template_config_variables_no_option(template, config_stub):
    with pytest.raises(configexc.NoOptionError):
        jinja.template_config_variables(template)