Skip to content

Commit 82762a2

Browse files
authored
fix: Escaping HTML in log (#757)
1 parent 84a1f68 commit 82762a2

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

src/pytest_html/basereport.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import re
99
import warnings
1010
from collections import defaultdict
11+
from html import escape
1112
from pathlib import Path
1213

1314
import pytest
@@ -312,11 +313,11 @@ def _is_error(report):
312313
def _process_logs(report):
313314
log = []
314315
if report.longreprtext:
315-
log.append(report.longreprtext.replace("<", "&lt;").replace(">", "&gt;") + "\n")
316+
log.append(escape(report.longreprtext) + "\n")
316317
# Don't add captured output to reruns
317318
if report.outcome != "rerun":
318319
for section in report.sections:
319-
header, content = section
320+
header, content = map(escape, section)
320321
log.append(f"{' ' + header + ' ':-^80}\n{content}")
321322

322323
# weird formatting related to logs

src/pytest_html/report_data.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44
import warnings
55
from collections import defaultdict
6+
from html import escape
67

78
from pytest_html.util import _handle_ansi
89

@@ -146,7 +147,7 @@ def append_teardown_log(self, report):
146147
# Last index is "call"
147148
test = self._data["tests"][report.nodeid][-1]
148149
for section in report.sections:
149-
header, content = section
150+
header, content = map(escape, section)
150151
if "teardown" in header:
151152
log.append(f"{' ' + header + ' ':-^80}\n{content}")
152153
test["log"] += _handle_ansi("\n".join(log))

testing/test_integration.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,42 @@ def test_pass(utf8):
787787
log = get_log(page)
788788
assert_that(log).does_not_match(r"测试用例名称")
789789

790+
@pytest.mark.parametrize("outcome, occurrence", [(True, 1), (False, 2)])
791+
def test_log_escaping(self, pytester, outcome, occurrence):
792+
"""
793+
Not the best test, but it does a simple verification
794+
that the string is escaped properly and not rendered as HTML
795+
"""
796+
texts = [
797+
"0 Checking object <Chopstick Container> and more",
798+
"1 Checking object < > and more",
799+
"2 Checking object <> and more",
800+
"3 Checking object < C > and more",
801+
"4 Checking object <C > and more",
802+
"5 Checking object < and more",
803+
"6 Checking object < and more",
804+
"7 Checking object < C and more",
805+
"8 Checking object <C and more",
806+
'9 Checking object "<Chopstick Container>" and more',
807+
'10 Checking object "< >" and more',
808+
'11 Checking object "<>" and more',
809+
'12 Checking object "< C >" and more',
810+
'13 Checking object "<C >" and more',
811+
]
812+
test_file = "def test_escape():\n"
813+
for t in texts:
814+
test_file += f"\tprint('{t}')\n"
815+
test_file += f"\tassert {outcome}"
816+
pytester.makepyfile(test_file)
817+
818+
page = run(pytester)
819+
assert_results(page, passed=1 if outcome else 0, failed=1 if not outcome else 0)
820+
821+
log = get_log(page)
822+
for each in texts:
823+
count = log.count(each)
824+
assert_that(count).is_equal_to(occurrence)
825+
790826

791827
class TestLogCapturing:
792828
LOG_LINE_REGEX = r"\s+this is {}"

0 commit comments

Comments
 (0)