Skip to content

Fix assets file naming to work across both *nix and windows #223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 12 additions & 16 deletions pytest_html/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
import sys
import time
import bisect
import hashlib
import warnings
import re

try:
from ansi2html import Ansi2HTMLConverter, style
Expand Down Expand Up @@ -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))

Expand Down Expand Up @@ -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"
)
Expand Down
54 changes: 30 additions & 24 deletions testing/test_pytest_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import pkg_resources
import random
import re
import hashlib

import pytest

Expand Down Expand Up @@ -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 = '<a class="text" href="{0}" target="_blank">'.format(src)
assert link in html
assert os.path.exists(src)
Expand All @@ -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 = '<a class="image" href="{0}" target="_blank">'.format(src)
assert link in html
Expand Down Expand Up @@ -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 = '<a class="image" href="{0}" target="_blank">'.format(src)
assert result.ret
assert link in html
Expand Down Expand Up @@ -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 = '<a class="image" href="{0}" target="_blank">'.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(
"""
Expand Down
3 changes: 2 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down