# ----------------------------------------------------------------------------# SymForce - Copyright 2022, Skydio, Inc.# This source code is under the Apache 2.0 license found in the LICENSE file.# ----------------------------------------------------------------------------importrandomimportsysimportunittestimportnumpyasnpimportsymforcefromsymforceimporttypingasTfromsymforce.test_util.test_case_mixinimportSymforceTestCaseMixin
[docs]classTestCase(SymforceTestCaseMixin):""" Base class for symforce tests. Adds some useful helpers. """# Set by the --run_slow_tests flag to indicate that we should run all tests even# if we're on SymPy._RUN_SLOW_TESTS=False
[docs]@staticmethoddefshould_run_slow_tests()->bool:# NOTE(aaron): This needs to be accessible before main() is called, so we do it here# instead. This should also be called from main to make sure it runs at least onceif"--run_slow_tests"insys.argv:TestCase._RUN_SLOW_TESTS=Truesys.argv.remove("--run_slow_tests")returnTestCase._RUN_SLOW_TESTS
[docs]@staticmethoddefmain(*args:T.Any,**kwargs:T.Any)->None:""" Call this to run all tests in scope. """TestCase.should_run_slow_tests()# unittest on py3.12 exits with _NO_TESTS_EXITCODE = 5 if no tests are found. As of# py3.12.1, this includes if all tests are skipped (which applies to some of our tests,# depending on symbolic API and installed packages). So, we monkey patch unittest to exit# with 0 in this case (including if no tests were found, which isn't great). This hack# can be removed once the fix is in a release:# https://github.com/python/cpython/commit/159e3db1f7697b9aecdf674bb833fbb87f3dcad3ifsys.version_info>=(3,12,0)andsys.version_info<(3,12,2):sys.modules[unittest.main.__module__]._NO_TESTS_EXITCODE=0# type: ignore[attr-defined] # noqa: SLF001SymforceTestCaseMixin.main(*args,**kwargs)
[docs]defsetUp(self)->None:super().setUp()# Set random seedsnp.random.seed(42)random.seed(42)# Store verbosity flag so tests can useself.verbose=("-v"insys.argv)or("--verbose"insys.argv)
[docs]defsympy_only(func:T.Callable)->T.Callable:""" Decorator to mark a test to only run on SymPy, and skip otherwise. """ifsymforce.get_symbolic_api()!="sympy":returnunittest.skip("This test only runs on SymPy symbolic API.")(func)else:returnfunc
[docs]defsymengine_only(func:T.Callable)->T.Callable:""" Decorator to mark a test to only run on the SymEngine, and skip otherwise. """ifsymforce.get_symbolic_api()!="symengine":returnunittest.skip("This test only runs on the SymEngine symbolic API")(func)else:returnfunc
[docs]defexpected_failure_on_sympy(func:T.Callable)->T.Callable:""" Decorator to mark a test to be expected to fail only on SymPy.. """ifsymforce.get_symbolic_api()=="sympy":returnunittest.expectedFailure(func)else:returnfunc
[docs]defslow_on_sympy(func:T.Callable)->T.Callable:""" Decorator to mark a test as slow on sympy. Will be skipped unless passed the ``--run_slow_tests`` flag """ifsymforce.get_symbolic_api()=="sympy"andnotTestCase.should_run_slow_tests():returnunittest.skip("This test is too slow on SymPy.")(func)else:returnfunc