diff --git a/pytest_html/plugin.py b/pytest_html/plugin.py
index d1f5f2d9..49578cba 100644
--- a/pytest_html/plugin.py
+++ b/pytest_html/plugin.py
@@ -14,8 +14,8 @@
import sys
import time
import bisect
-import hashlib
import warnings
+import re
try:
from ansi2html import Ansi2HTMLConverter, style
@@ -167,21 +167,17 @@ def __lt__(self, other):
def create_asset(
self, content, extra_index, test_index, file_extension, mode="w"
):
-
- hash_key = "".join([self.test_id, str(extra_index), str(test_index)])
- hash_generator = hashlib.md5()
- hash_generator.update(hash_key.encode("utf-8"))
- hex_digest = hash_generator.hexdigest()
- # 255 is the common max filename length on various filesystems,
- # we subtract hash length, file extension length and 2 more
- # characters for the underscore and dot
- max_length = 255 - len(hex_digest) - len(file_extension) - 2
- asset_file_name = "{0}_{1}.{2}".format(
- hash_key[:max_length], hex_digest, file_extension
- )
+ # 255 is the common max filename length on various filesystems
+ asset_file_name = "{}_{}_{}.{}".format(
+ re.sub(r"[^\w\.]", "_", self.test_id),
+ str(extra_index),
+ str(test_index),
+ file_extension,
+ )[-255:]
asset_path = os.path.join(
os.path.dirname(self.logfile), "assets", asset_file_name
)
+
if not os.path.exists(os.path.dirname(asset_path)):
os.makedirs(os.path.dirname(asset_path))
@@ -217,9 +213,9 @@ def append_extra_html(self, extra, extra_index, test_index):
html_div = html.img(src=src)
else:
if PY3:
- content = b64decode(content.encode("utf-8"))
- else:
- content = b64decode(content)
+ content = content.encode("utf-8")
+
+ content = b64decode(content)
href = src = self.create_asset(
content, extra_index, test_index, extra.get("extension"), "wb"
)
diff --git a/testing/test_pytest_html.py b/testing/test_pytest_html.py
index 76bdc839..c7309a40 100644
--- a/testing/test_pytest_html.py
+++ b/testing/test_pytest_html.py
@@ -10,7 +10,6 @@
import pkg_resources
import random
import re
-import hashlib
import pytest
@@ -468,13 +467,8 @@ def pytest_runtest_makereport(item, call):
)
testdir.makepyfile("def test_pass(): pass")
result, html = run(testdir)
- hash_key = "test_extra_text_separated.py::" "test_pass00"
- hash_generator = hashlib.md5()
- hash_generator.update(hash_key.encode("utf-8"))
assert result.ret == 0
- src = "{0}/{1}".format(
- "assets", "{0}_{1}.txt".format(hash_key, hash_generator.hexdigest())
- )
+ src = "assets/test_extra_text_separated.py__test_pass_0_0.txt"
link = ''.format(src)
assert link in html
assert os.path.exists(src)
@@ -501,13 +495,9 @@ def pytest_runtest_makereport(item, call):
)
testdir.makepyfile("def test_pass(): pass")
result, html = run(testdir)
- hash_key = "test_extra_image_separated.py::test_pass00"
- hash_generator = hashlib.md5()
- hash_generator.update(hash_key.encode("utf-8"))
assert result.ret == 0
- src = "{0}/{1}".format(
- "assets",
- "{0}_{1}.{2}".format(hash_key, hash_generator.hexdigest(), file_extension),
+ src = "assets/test_extra_image_separated.py__test_pass_0_0.{}".format(
+ file_extension
)
link = ''.format(src)
assert link in html
@@ -543,12 +533,8 @@ def test_fail():
result, html = run(testdir)
for i in range(1, 4):
- hash_key = "test_extra_image_separated_rerun.py::" "test_fail0{0}".format(i)
- hash_generator = hashlib.md5()
- hash_generator.update(hash_key.encode("utf-8"))
- src = "assets/{0}_{1}.{2}".format(
- hash_key, hash_generator.hexdigest(), file_extension
- )
+ asset_name = "test_extra_image_separated_rerun.py__test_fail"
+ src = "assets/{}_0_{}.{}".format(asset_name, i, file_extension)
link = ''.format(src)
assert result.ret
assert link in html
@@ -602,16 +588,36 @@ def {0}():
)
)
result, html = run(testdir)
-
- hash_key = "test_very_long_test_name.py::{}00".format(test_name)
- hash_generator = hashlib.md5()
- hash_generator.update(hash_key.encode("utf-8"))
- src = "assets/{0}_{1}.png".format(hash_key[:218], hash_generator.hexdigest())
+ file_name = "test_very_long_test_name.py__{}_0_0.png".format(test_name)[-255:]
+ src = "assets/" + file_name
link = ''.format(src)
assert result.ret
assert link in html
assert os.path.exists(src)
+ def test_no_invalid_characters_in_filename(self, testdir):
+ testdir.makeconftest(
+ """
+ import pytest
+ @pytest.hookimpl(hookwrapper=True)
+ def pytest_runtest_makereport(item, call):
+ outcome = yield
+ report = outcome.get_result()
+ if report.when == 'call':
+ from pytest_html import extras
+ report.extra = [extras.image('image.png')]
+ """
+ )
+ testdir.makepyfile(
+ """
+ def test_fail():
+ assert False
+ """
+ )
+ run(testdir)
+ for filename in os.listdir("assets"):
+ assert re.search(r'[:\\<>\*\?\|"}{}~]', filename) is None
+
def test_no_environment(self, testdir):
testdir.makeconftest(
"""
diff --git a/tox.ini b/tox.ini
index 1489252b..5c6a4fb3 100644
--- a/tox.ini
+++ b/tox.ini
@@ -7,12 +7,13 @@
envlist = py{27,36,37,py,py3}{,-ansi2html}, flake8, black
[testenv]
-commands = pytest -v -r a {posargs}
+setenv = PYTHONDONTWRITEBYTECODE=1
deps =
pytest-xdist
pytest-rerunfailures
pytest-mock
py{27,36,py,py3}-ansi2html: ansi2html
+commands = pytest -v -r a {posargs}
[testenv:flake8]
skip_install = true