Skip to content

Commit

Permalink
Failed fixtures don't break test name templating from fixture values (a…
Browse files Browse the repository at this point in the history
  • Loading branch information
skhomuti authored Oct 10, 2022
1 parent e5b028d commit db49669
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
4 changes: 2 additions & 2 deletions allure-pytest/src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import six
import pytest
from itertools import chain, islice
from allure_commons.utils import represent
from allure_commons.utils import represent, SafeFormatter
from allure_commons.utils import format_exception, format_traceback, escape_non_unicode_symbols
from allure_commons.model2 import Status
from allure_commons.model2 import StatusDetails
Expand Down Expand Up @@ -111,7 +111,7 @@ def allure_package(item):
def allure_name(item, parameters):
name = escape_name(item.name)
title = allure_title(item)
return title.format(**{**parameters, **item.funcargs}) if title else name
return SafeFormatter().format(title, **{**parameters, **item.funcargs}) if title else name


def allure_full_name(item):
Expand Down
21 changes: 21 additions & 0 deletions allure-pytest/test/acceptance/display_name/display_name_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,24 @@ def test_feature_label_for_titled_test():
has_title("Titled test with features")
)
)


def test_failed_fixture_value_in_display_name(executed_docstring_source):
"""
>>> import allure
>>> import pytest
>>> @pytest.fixture
... def fix():
... raise AssertionError("Fixture failed for some reason")
>>> @allure.title('title with {fix}')
... def test_fixture_value_name(fix):
... pass
"""

assert_that(executed_docstring_source.allure_report,
has_test_case("test_fixture_value_name",
has_title("title with {fix}")
)
)
51 changes: 51 additions & 0 deletions allure-python-commons/src/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-

import os
import string
import sys
import six
import time
Expand Down Expand Up @@ -404,3 +405,53 @@ def get_testplan():
planned_tests = plan.get("tests", [])

return planned_tests


class SafeFormatter(string.Formatter):
"""
Format string safely - skip any non-passed keys
>>> f = SafeFormatter().format
Make sure we don't broke default formatting behaviour
>>> f("literal string")
'literal string'
>>> f("{expected.format}", expected=str)
"<method 'format' of 'str' objects>"
>>> f("{expected[0]}", expected=["value"])
'value'
>>> f("{expected[0]}", expected=123)
Traceback (most recent call last):
...
TypeError: 'int' object is not subscriptable
>>> f("{expected[0]}", expected=[])
Traceback (most recent call last):
...
IndexError: list index out of range
>>> f("{expected.format}", expected=int)
Traceback (most recent call last):
...
AttributeError: type object 'int' has no attribute 'format'
Check that unexpected keys do not cause some errors
>>> f("{expected} {unexpected}", expected="value")
'value {unexpected}'
>>> f("{unexpected[0]}", expected=["value"])
'{unexpected[0]}'
>>> f("{unexpected.format}", expected=str)
'{unexpected.format}'
"""

class SafeKeyOrIndexError(Exception):
pass

def get_field(self, field_name, args, kwargs):
try:
return super().get_field(field_name, args, kwargs)
except self.SafeKeyOrIndexError:
return "{" + field_name + "}", field_name

def get_value(self, key, args, kwargs):
try:
return super().get_value(key, args, kwargs)
except (KeyError, IndexError):
raise self.SafeKeyOrIndexError()

0 comments on commit db49669

Please sign in to comment.