 c0244f3018
			
		
	
	c0244f3018
	
	
	
		
			
			* Tests: unroll test_multiworlds.TestTwoPlayerMulti Also adds a helper function that other tests can use to unroll tests. * Docs: add more details to docs/tests.md * Explain parametrization, subtests and link to the new helper * Mention some performance details and work-arounds * Mention multithreading / pytest-xdist * Tests: make param.classvar_matrix accept sets * CI: add test/param.py to type checking * Tests: add missing typing to test/param.py * Tests: fix typo in test/param.py doc comment Co-authored-by: qwint <qwint.42@gmail.com> * update docs * Docs: reword note on performance --------- Co-authored-by: qwint <qwint.42@gmail.com>
		
			
				
	
	
		
			47 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			47 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import itertools
 | |
| import sys
 | |
| from typing import Any, Callable, Iterable
 | |
| 
 | |
| 
 | |
| def classvar_matrix(**kwargs: Iterable[Any]) -> Callable[[type], None]:
 | |
|     """
 | |
|     Create a new class for each variation of input, allowing to generate a TestCase matrix / parametrization that
 | |
|     supports multi-threading and has better reporting for ``unittest --durations=...`` and ``pytest --durations=...``
 | |
|     than subtests.
 | |
| 
 | |
|     The kwargs will be set as ClassVars in the newly created classes. Use as ::
 | |
| 
 | |
|         @classvar_matrix(var_name=[value1, value2])
 | |
|         class MyTestCase(unittest.TestCase):
 | |
|             var_name: typing.ClassVar[...]
 | |
| 
 | |
|     :param kwargs: A dict of ClassVars to set, where key is the variable name and value is a list of all values.
 | |
|     :return: A decorator to be applied to a class.
 | |
|     """
 | |
|     keys: tuple[str]
 | |
|     values: Iterable[Iterable[Any]]
 | |
|     keys, values = zip(*kwargs.items())
 | |
|     values = map(lambda v: sorted(v) if isinstance(v, (set, frozenset)) else v, values)
 | |
|     permutations_dicts = [dict(zip(keys, v)) for v in itertools.product(*values)]
 | |
| 
 | |
|     def decorator(cls: type) -> None:
 | |
|         mod = sys.modules[cls.__module__]
 | |
| 
 | |
|         for permutation in permutations_dicts:
 | |
| 
 | |
|             class Unrolled(cls):  # type: ignore
 | |
|                 pass
 | |
| 
 | |
|             for k, v in permutation.items():
 | |
|                 setattr(Unrolled, k, v)
 | |
|             params = ", ".join([f"{k}={repr(v)}" for k, v in permutation.items()])
 | |
|             params = f"{{{params}}}"
 | |
| 
 | |
|             Unrolled.__module__ = cls.__module__
 | |
|             Unrolled.__qualname__ = f"{cls.__qualname__}{params}"
 | |
|             setattr(mod, f"{cls.__name__}{params}", Unrolled)
 | |
| 
 | |
|         return None
 | |
| 
 | |
|     return decorator
 |