""" Tests for safe_template_linter.py """ from ddt import ddt, data import textwrap from unittest import TestCase from ..safe_template_linter import ( FileResults, MakoTemplateLinter, Rules ) @ddt class TestMakoTemplateLinter(TestCase): """ Test MakoTemplateLinter """ @data( {'directory': 'lms/templates', 'expected': True}, {'directory': 'lms/templates/support', 'expected': True}, {'directory': 'lms/templates/support', 'expected': True}, {'directory': './test_root/staticfiles/templates', 'expected': False}, {'directory': './some/random/path', 'expected': False}, ) def test_is_mako_directory(self, data): """ Test _is_mako_directory correctly determines mako directories """ linter = MakoTemplateLinter() self.assertEqual(linter._is_mako_directory(data['directory']), data['expected']) def test_check_page_default_with_default_provided(self): """ Test _check_mako_file_is_safe with default causes no violation """ linter = MakoTemplateLinter() results = FileResults('') mako_template = """ <%page expression_filter="h"/> """ linter._check_mako_file_is_safe(mako_template, results) self.assertEqual(len(results.violations), 0) def test_check_page_default_with_no_default_provided(self): """ Test _check_mako_file_is_safe with no default causes violation """ linter = MakoTemplateLinter() results = FileResults('') mako_template = "" linter._check_mako_file_is_safe(mako_template, results) self.assertEqual(len(results.violations), 1) self.assertEqual(results.violations[0].rule, Rules.mako_missing_default) def test_check_mako_expressions_in_html(self): """ Test _check_mako_file_is_safe in html context provides appropriate violations """ linter = MakoTemplateLinter() results = FileResults('') mako_template = textwrap.dedent(""" <%page expression_filter="h"/> ${x} ${'{{unbalanced-nested'} ${x | n} ${x | h} ${x | n, dump_html_escaped_json} ${x | n, dump_js_escaped_json} """) linter._check_mako_file_is_safe(mako_template, results) self.assertEqual(len(results.violations), 4) self.assertEqual(results.violations[0].rule, Rules.mako_unparsable_expression) start_index = results.violations[0].expression['start_index'] self.assertEqual(mako_template[start_index:start_index + 24], "${'{{unbalanced-nested'}") self.assertEqual(results.violations[1].rule, Rules.mako_invalid_html_filter) self.assertEqual(results.violations[1].expression['expression'], "${x | n}") self.assertEqual(results.violations[2].rule, Rules.mako_unwanted_html_filter) self.assertEqual(results.violations[2].expression['expression'], "${x | h}") self.assertEqual(results.violations[3].rule, Rules.mako_invalid_html_filter) self.assertEqual(results.violations[3].expression['expression'], "${x | n, dump_js_escaped_json}") def test_check_mako_expressions_in_html_without_default(self): """ Test _check_mako_file_is_safe in html context without the page level default h filter suppresses expression level violation """ linter = MakoTemplateLinter() results = FileResults('') mako_template = textwrap.dedent(""" ${x | h} """) linter._check_mako_file_is_safe(mako_template, results) self.assertEqual(len(results.violations), 1) self.assertEqual(results.violations[0].rule, Rules.mako_missing_default) def test_check_mako_expressions_in_javascript(self): """ Test _check_mako_file_is_safe in JavaScript script context provides appropriate violations """ linter = MakoTemplateLinter() results = FileResults('') mako_template = textwrap.dedent(""" <%page expression_filter="h"/> """) linter._check_mako_file_is_safe(mako_template, results) self.assertEqual(len(results.violations), 6) self.assertEqual(results.violations[0].rule, Rules.mako_invalid_js_filter) self.assertEqual(results.violations[0].expression['expression'], "${x}") self.assertEqual(results.violations[1].rule, Rules.mako_unparsable_expression) start_index = results.violations[1].expression['start_index'] self.assertEqual(mako_template[start_index:start_index + 24], "${'{{unbalanced-nested'}") self.assertEqual(results.violations[2].rule, Rules.mako_invalid_js_filter) self.assertEqual(results.violations[2].expression['expression'], "${x | n}") self.assertEqual(results.violations[3].rule, Rules.mako_invalid_js_filter) self.assertEqual(results.violations[3].expression['expression'], "${x | h}") self.assertEqual(results.violations[4].rule, Rules.mako_invalid_js_filter) self.assertEqual(results.violations[4].expression['expression'], "${x | n, dump_html_escaped_json}") self.assertEqual(results.violations[5].rule, Rules.mako_js_string_missing_quotes) self.assertEqual(results.violations[5].expression['expression'], "${x-missing-quotes | n, js_escaped_string}") def test_check_mako_expressions_in_require_js(self): """ Test _check_mako_file_is_safe in JavaScript require context provides appropriate violations """ linter = MakoTemplateLinter() results = FileResults('') mako_template = textwrap.dedent(""" <%page expression_filter="h"/> <%static:require_module module_name="${x}" class_name="TestFactory"> ${x} ${x | n, js_escaped_string} %static:require_module> """) linter._check_mako_file_is_safe(mako_template, results) self.assertEqual(len(results.violations), 2) self.assertEqual(results.violations[0].rule, Rules.mako_invalid_js_filter) self.assertEqual(results.violations[0].expression['expression'], "${x}") self.assertEqual(results.violations[1].rule, Rules.mako_js_string_missing_quotes) self.assertEqual(results.violations[1].expression['expression'], "${x | n, js_escaped_string}") @data( {'media_type': 'text/javascript', 'expected_violations': 0}, {'media_type': 'text/ecmascript', 'expected_violations': 0}, {'media_type': 'application/ecmascript', 'expected_violations': 0}, {'media_type': 'application/javascript', 'expected_violations': 0}, {'media_type': 'text/template', 'expected_violations': 1}, {'media_type': 'unknown/type', 'expected_violations': 1}, ) def test_check_mako_expressions_in_script_type(self, data): """ Test _check_mako_file_is_safe in script tag with different media types """ linter = MakoTemplateLinter() results = FileResults('') mako_template = textwrap.dedent(""" <%page expression_filter="h"/> """).format(data['media_type']) linter._check_mako_file_is_safe(mako_template, results) self.assertEqual(len(results.violations), data['expected_violations']) def test_check_mako_expressions_in_mixed_contexts(self): """ Test _check_mako_file_is_safe in mixed contexts provides appropriate violations """ linter = MakoTemplateLinter() results = FileResults('') mako_template = textwrap.dedent(""" <%page expression_filter="h"/> ${x | h} ${x | h} <%static:require_module module_name="${x}" class_name="TestFactory"> ${x | h} %static:require_module> ${x | h} """) linter._check_mako_file_is_safe(mako_template, results) self.assertEqual(len(results.violations), 5) self.assertEqual(results.violations[0].rule, Rules.mako_unwanted_html_filter) self.assertEqual(results.violations[1].rule, Rules.mako_invalid_js_filter) self.assertEqual(results.violations[2].rule, Rules.mako_unwanted_html_filter) self.assertEqual(results.violations[3].rule, Rules.mako_invalid_js_filter) self.assertEqual(results.violations[4].rule, Rules.mako_unwanted_html_filter) def test_expression_detailed_results(self): """ Test _check_mako_file_is_safe provides detailed results, including line numbers, columns, and line """ linter = MakoTemplateLinter() results = FileResults('') mako_template = textwrap.dedent(""" ${x | n}