mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	We now properly parse HTML comments that have HTML block tags or handlebars/Django blocks within them.
		
			
				
	
	
		
			245 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from __future__ import absolute_import
 | 
						|
from __future__ import print_function
 | 
						|
 | 
						|
from typing import Optional, Any
 | 
						|
 | 
						|
import sys
 | 
						|
import unittest
 | 
						|
 | 
						|
try:
 | 
						|
    from tools.lib.template_parser import (
 | 
						|
        TemplateParserException,
 | 
						|
        is_django_block_tag,
 | 
						|
        tokenize,
 | 
						|
        validate,
 | 
						|
    )
 | 
						|
except ImportError:
 | 
						|
    print('ERROR!!! You need to run this via tools/test-tools.')
 | 
						|
    sys.exit(1)
 | 
						|
 | 
						|
class ParserTest(unittest.TestCase):
 | 
						|
    def __init__(self, *args, **kwargs):
 | 
						|
        # type: (*Any, **Any) -> None
 | 
						|
        # This method should be removed when we migrate to version 3 of Python
 | 
						|
        import six
 | 
						|
        if six.PY2:
 | 
						|
            self.assertRaisesRegex = self.assertRaisesRegexp  # type: ignore
 | 
						|
        super(ParserTest, self).__init__(*args, **kwargs)
 | 
						|
 | 
						|
    def _assert_validate_error(self, error, fn=None, text=None, check_indent=True):
 | 
						|
        # type: (str, Optional[str], Optional[str], bool) -> None
 | 
						|
        with self.assertRaisesRegex(TemplateParserException, error): # type: ignore # See https://github.com/python/typeshed/issues/372
 | 
						|
            validate(fn=fn, text=text, check_indent=check_indent)
 | 
						|
 | 
						|
    def test_is_django_block_tag(self):
 | 
						|
        # type: () -> None
 | 
						|
        self.assertTrue(is_django_block_tag('block'))
 | 
						|
        self.assertFalse(is_django_block_tag('not a django tag'))
 | 
						|
 | 
						|
    def test_validate_vanilla_html(self):
 | 
						|
        # type: () -> None
 | 
						|
        '''
 | 
						|
        Verify that validate() does not raise errors for
 | 
						|
        well-formed HTML.
 | 
						|
        '''
 | 
						|
        my_html = '''
 | 
						|
            <table>
 | 
						|
                <tr>
 | 
						|
                <td>foo</td>
 | 
						|
                </tr>
 | 
						|
            </table>'''
 | 
						|
        validate(text=my_html)
 | 
						|
 | 
						|
    def test_validate_handlebars(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            {{#with stream}}
 | 
						|
                <p>{{stream}}</p>
 | 
						|
            {{/with}}
 | 
						|
            '''
 | 
						|
        validate(text=my_html)
 | 
						|
 | 
						|
    def test_validate_comment(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            <!---
 | 
						|
                <h1>foo</h1>
 | 
						|
            -->'''
 | 
						|
        validate(text=my_html)
 | 
						|
 | 
						|
    def test_validate_django(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            {% include "some_other.html" %}
 | 
						|
            {% if foo %}
 | 
						|
                <p>bar</p>
 | 
						|
            {% endif %}
 | 
						|
            '''
 | 
						|
        validate(text=my_html)
 | 
						|
 | 
						|
    def test_validate_no_start_tag(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            foo</p>
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('No start tag', text=my_html)
 | 
						|
 | 
						|
    def test_validate_mismatched_tag(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            <b>foo</i>
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('Mismatched tag.', text=my_html)
 | 
						|
 | 
						|
    def test_validate_bad_indentation(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            <p>
 | 
						|
                foo
 | 
						|
                </p>
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('Bad indentation.', text=my_html, check_indent=True)
 | 
						|
 | 
						|
    def test_validate_state_depth(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            <b>
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('Missing end tag', text=my_html)
 | 
						|
 | 
						|
    def test_validate_incomplete_handlebars_tag_1(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            {{# foo
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('Tag missing }}', text=my_html)
 | 
						|
 | 
						|
    def test_validate_incomplete_handlebars_tag_2(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            {{# foo }
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('Tag missing }}', text=my_html)
 | 
						|
 | 
						|
    def test_validate_incomplete_django_tag_1(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            {% foo
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('Tag missing %}', text=my_html)
 | 
						|
 | 
						|
    def test_validate_incomplete_django_tag_2(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            {% foo %
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('Tag missing %}', text=my_html)
 | 
						|
 | 
						|
    def test_validate_incomplete_html_tag_1(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            <b
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('Tag missing >', text=my_html)
 | 
						|
 | 
						|
    def test_validate_incomplete_html_tag_2(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            <a href="
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('Tag missing >', text=my_html)
 | 
						|
 | 
						|
    def test_validate_empty_html_tag(self):
 | 
						|
        # type: () -> None
 | 
						|
        my_html = '''
 | 
						|
            < >
 | 
						|
        '''
 | 
						|
        self._assert_validate_error('Tag name missing', text=my_html)
 | 
						|
 | 
						|
    def test_code_blocks(self):
 | 
						|
        # type: () -> None
 | 
						|
 | 
						|
        # This is fine.
 | 
						|
        my_html = '''
 | 
						|
            <code>
 | 
						|
                x = 5
 | 
						|
                y = x + 1
 | 
						|
            </code>'''
 | 
						|
        validate(text=my_html)
 | 
						|
 | 
						|
        # This is also fine.
 | 
						|
        my_html = "<code>process_widgets()</code>"
 | 
						|
        validate(text=my_html)
 | 
						|
 | 
						|
        # This is illegal.
 | 
						|
        my_html = '''
 | 
						|
            <code>x =
 | 
						|
            5</code>
 | 
						|
            '''
 | 
						|
        self._assert_validate_error('Code tag is split across two lines.', text=my_html)
 | 
						|
 | 
						|
    def test_anchor_blocks(self):
 | 
						|
        # type: () -> None
 | 
						|
 | 
						|
        # This is allowed, although strange.
 | 
						|
        my_html = '''
 | 
						|
            <a hef="/some/url">
 | 
						|
            Click here
 | 
						|
            for more info.
 | 
						|
            </a>'''
 | 
						|
        validate(text=my_html)
 | 
						|
 | 
						|
        # This is fine.
 | 
						|
        my_html = '<a href="/some/url">click here</a>'
 | 
						|
        validate(text=my_html)
 | 
						|
 | 
						|
        # Even this is fine.
 | 
						|
        my_html = '''
 | 
						|
            <a class="twitter-timeline" href="https://twitter.com/ZulipStatus"
 | 
						|
                data-widget-id="443457763394334720"
 | 
						|
                data-screen-name="ZulipStatus"
 | 
						|
                >@ZulipStatus on Twitter</a>.
 | 
						|
            '''
 | 
						|
        validate(text=my_html)
 | 
						|
 | 
						|
    def test_tokenize(self):
 | 
						|
        # type: () -> None
 | 
						|
        tag = '<meta whatever>bla'
 | 
						|
        token = tokenize(tag)[0]
 | 
						|
        self.assertEqual(token.kind, 'html_special')
 | 
						|
 | 
						|
        tag = '<a>bla'
 | 
						|
        token = tokenize(tag)[0]
 | 
						|
        self.assertEqual(token.kind, 'html_start')
 | 
						|
        self.assertEqual(token.tag, 'a')
 | 
						|
 | 
						|
        tag = '<br />bla'
 | 
						|
        token = tokenize(tag)[0]
 | 
						|
        self.assertEqual(token.kind, 'html_singleton')
 | 
						|
        self.assertEqual(token.tag, 'br')
 | 
						|
 | 
						|
        tag = '</a>bla'
 | 
						|
        token = tokenize(tag)[0]
 | 
						|
        self.assertEqual(token.kind, 'html_end')
 | 
						|
        self.assertEqual(token.tag, 'a')
 | 
						|
 | 
						|
        tag = '{{#with foo}}bla'
 | 
						|
        token = tokenize(tag)[0]
 | 
						|
        self.assertEqual(token.kind, 'handlebars_start')
 | 
						|
        self.assertEqual(token.tag, 'with')
 | 
						|
 | 
						|
        tag = '{{/with}}bla'
 | 
						|
        token = tokenize(tag)[0]
 | 
						|
        self.assertEqual(token.kind, 'handlebars_end')
 | 
						|
        self.assertEqual(token.tag, 'with')
 | 
						|
 | 
						|
        tag = '{% if foo %}bla'
 | 
						|
        token = tokenize(tag)[0]
 | 
						|
        self.assertEqual(token.kind, 'django_start')
 | 
						|
        self.assertEqual(token.tag, 'if')
 | 
						|
 | 
						|
        tag = '{% endif %}bla'
 | 
						|
        token = tokenize(tag)[0]
 | 
						|
        self.assertEqual(token.kind, 'django_end')
 | 
						|
        self.assertEqual(token.tag, 'if')
 |