Skip to content
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
6 changes: 6 additions & 0 deletions doc/en/multitest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,12 @@ In the above example, the custom testcase names should be
``'Add List 0'`` and ``'Add List 1'``, that is, integer suffixes appended to
the original testcase names, without any argument showed.

A generated name longer than 255 characters cannot be used, so Testplan warns
and falls back to the integer-suffixed names described above. Set the
``TESTPLAN_STRICT_PARAM_NAMES=1`` environment variable to instead raise
``ParametrizationNameError`` at import time, failing fast rather than degrading
to index-suffixed names.

.. _parametrization_docstring_func:

Testcase docstring generation
Expand Down
1 change: 1 addition & 0 deletions doc/newsfragments/3852_changed.strict_param_names.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Setting the ``TESTPLAN_STRICT_PARAM_NAMES=1`` environment variable now makes an over-long parametrized testcase name raise an error instead of falling back to an index-suffixed name with a warning.
27 changes: 27 additions & 0 deletions testplan/testing/multitest/parametrization.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import collections
import itertools
import os
import re
import warnings

Expand All @@ -23,11 +24,33 @@
# Python attribute names can be of unlimited length but we set a limit here
MAX_METHOD_NAME_LENGTH = 255

STRICT_PARAM_NAMES_ENV = "TESTPLAN_STRICT_PARAM_NAMES"


def _strict_param_names() -> bool:
"""
Whether strict parametrized name generation is enabled. Read from the
environment on each call (not cached at import time) so it reflects the
running environment and can be toggled in tests.
"""
return os.environ.get(STRICT_PARAM_NAMES_ENV) == "1"


class ParametrizationError(ValueError):
pass


class ParametrizationNameError(ParametrizationError):
"""
Raised in strict mode when a generated parametrized testcase name cannot be used as it exceeds ``MAX_METHOD_NAME_LENGTH``.
"""

def __init__(self, name: str):
super().__init__(
f"Generated parametrized testcase name ({name}) exceeds {MAX_METHOD_NAME_LENGTH} characters."
)


def _check_dict_keys(dictionary, args, required_args):
dict_keys = set(dictionary.keys())

Expand Down Expand Up @@ -331,6 +354,8 @@ def _parametrization_name_func_wrapper(func_name: str, kwargs: dict):
if len(generated_name) > MAX_METHOD_NAME_LENGTH:
# Generated method name is a bit too long.
# Index suffixed names, e.g. "{func_name}__1", "{func_name}__2", will be used.
if _strict_param_names():
raise ParametrizationNameError(generated_name)
return func_name

return generated_name
Expand Down Expand Up @@ -358,6 +383,8 @@ def _parametrization_report_name_func_wrapper(
)
if len(generated_name) <= MAX_METHOD_NAME_LENGTH:
return generated_name
elif _strict_param_names():
raise ParametrizationNameError(generated_name)
else:
warnings.warn(
f"The name name_func returned ({generated_name}) is too long, using index suffixed names."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
from testplan.testing.multitest import MultiTest, testsuite, testcase
from testplan.testing.multitest.parametrization import (
MAX_METHOD_NAME_LENGTH,
STRICT_PARAM_NAMES_ENV,
ParametrizationError,
ParametrizationNameError,
)
from testplan.report import (
TestReport,
Expand Down Expand Up @@ -530,6 +532,65 @@ def sample_test(self, env, result, val):
mockplan.run()


def test_strict_param_names_report_name_too_long(monkeypatch):
"""
In strict mode, an over-long name returned by ``name_func`` should raise
``ParametrizationNameError`` at decoration time instead of warning.
"""
monkeypatch.setenv(STRICT_PARAM_NAMES_ENV, "1")
long_string = "c" * (MAX_METHOD_NAME_LENGTH + 1)

with pytest.raises(ParametrizationNameError, match="exceeds"):

@testsuite
class MySuite:
@testcase(
parameters=(1,),
name_func=lambda func_name, kwargs: long_string,
)
def sample_test(self, env, result, val):
pass


def test_strict_param_names_method_name_too_long(monkeypatch):
"""
In strict mode, parameters that produce an over-long generated method
name should raise ``ParametrizationNameError`` at decoration time.
"""
monkeypatch.setenv(STRICT_PARAM_NAMES_ENV, "1")

with pytest.raises(ParametrizationNameError, match="exceeds"):

@testsuite
class MySuite:
@testcase(parameters=("a" * MAX_METHOD_NAME_LENGTH,))
def sample_test(self, env, result, val):
pass


def test_strict_param_names_disabled_still_warns(monkeypatch):
"""
With the env var unset (default), the old warn + index-suffixed fallback
behavior should be preserved.
"""
monkeypatch.delenv(STRICT_PARAM_NAMES_ENV, raising=False)
long_string = "c" * (MAX_METHOD_NAME_LENGTH + 1)

with pytest.warns(
UserWarning,
match=f"The name name_func returned \\({long_string}\\) is too long, using index suffixed names.",
):

@testsuite
class MySuite:
@testcase(
parameters=(1,),
name_func=lambda func_name, kwargs: long_string,
)
def sample_test(self, env, result, val):
pass


def test_custom_wrapper():
"""Custom wrappers should be applied to each generated testcase."""

Expand Down
Loading