mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-03-04 09:33:54 +08:00
48 lines
1.7 KiB
Python
48 lines
1.7 KiB
Python
import sys
|
|
import pytest
|
|
import inspect
|
|
|
|
|
|
class parameterized:
|
|
@staticmethod
|
|
def expand(cases):
|
|
cases = list(cases)
|
|
|
|
if not cases:
|
|
return lambda func: pytest.mark.skip("no parameterized cases")(func)
|
|
|
|
def decorator(func):
|
|
params = [p for p in inspect.signature(func).parameters if p != 'self']
|
|
normalized = [c if isinstance(c, tuple) else (c,) for c in cases]
|
|
# Infer arg count from first case so extra params (e.g. from @given) are left untouched
|
|
expand_params = params[: len(normalized[0])]
|
|
if len(expand_params) == 1:
|
|
return pytest.mark.parametrize(expand_params[0], [c[0] for c in normalized])(func)
|
|
return pytest.mark.parametrize(', '.join(expand_params), normalized)(func)
|
|
|
|
return decorator
|
|
|
|
|
|
def parameterized_class(attrs, input_list=None):
|
|
if isinstance(attrs, list) and (not attrs or isinstance(attrs[0], dict)):
|
|
params_list = attrs
|
|
else:
|
|
assert input_list is not None
|
|
attr_names = (attrs,) if isinstance(attrs, str) else tuple(attrs)
|
|
params_list = [dict(zip(attr_names, v if isinstance(v, (tuple, list)) else (v,), strict=False)) for v in input_list]
|
|
|
|
def decorator(cls):
|
|
globs = sys._getframe(1).f_globals
|
|
for i, params in enumerate(params_list):
|
|
name = f"{cls.__name__}_{i}"
|
|
new_cls = type(name, (cls,), dict(params))
|
|
new_cls.__module__ = cls.__module__
|
|
new_cls.__test__ = True # override inherited False so pytest collects this subclass
|
|
globs[name] = new_cls
|
|
# Don't collect the un-parametrised base, but return it so outer decorators
|
|
# (e.g. @pytest.mark.skip) land on it and propagate to subclasses via MRO.
|
|
cls.__test__ = False
|
|
return cls
|
|
|
|
return decorator
|