From 541a4e705296fc5699bfedd334c4c0dfed8751ea Mon Sep 17 00:00:00 2001 From: MarcZX100 Date: Wed, 14 Oct 2026 06:04:39 +0000 Subject: [PATCH] test(tools): shard conventions comment checks under CTest timeout --- CMakeLists.txt | 12 ++++- .../tests/test_check_conventions_comments.py | 45 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c47828842..261c4e031f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,8 +109,16 @@ if(BUILD_TESTING) ${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_import_audit.py) add_test(NAME unwrap_self COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_unwrap_self.py) - add_test(NAME conventions_function_bodies COMMAND ${Python3_EXECUTABLE} - ${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_comments.py) + foreach(shard RANGE 0 5) + if(shard EQUAL 0) + set(conventions_test_name conventions_function_bodies) + else() + set(conventions_test_name conventions_function_bodies_shard_${shard}) + endif() + add_test(NAME ${conventions_test_name} COMMAND ${Python3_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_comments.py --shard ${shard}/6) + set_tests_properties(${conventions_test_name} PROPERTIES TIMEOUT 30) + endforeach() add_test(NAME conventions_wrapped_declarations COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_wrapped_declarations.py) add_test(NAME conventions_ci_gate COMMAND ${Python3_EXECUTABLE} diff --git a/tools/tests/test_check_conventions_comments.py b/tools/tests/test_check_conventions_comments.py index 25e0b1f871..e06c3c4386 100644 --- a/tools/tests/test_check_conventions_comments.py +++ b/tools/tests/test_check_conventions_comments.py @@ -11,6 +11,39 @@ from unittest.mock import patch sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from check_conventions import STUB_BODY, SYSTEM_DEPENDENCY, Check, function_body, links, output +CONVENTIONS_TEST_SHARDS = 6 + + +def iter_test_cases(suite): + for test in suite: + if isinstance(test, unittest.TestSuite): + yield from iter_test_cases(test) + else: + yield test + + +def discovered_test_cases(): + suite = unittest.defaultTestLoader.loadTestsFromModule(sys.modules[__name__]) + return sorted(iter_test_cases(suite), key=lambda test: test.id()) + + +def conventions_test_shard(shard, shard_count=CONVENTIONS_TEST_SHARDS): + if shard_count <= 0 or shard < 0 or shard >= shard_count: + raise ValueError("shard index must be within the shard count") + tests = discovered_test_cases() + return unittest.TestSuite(test for index, test in enumerate(tests) if index % shard_count == shard) + + +class TestShardTests(unittest.TestCase): + def test_shards_discover_each_case_once(self): + discovered = [test.id() for test in discovered_test_cases()] + sharded = [test.id() for shard in range(CONVENTIONS_TEST_SHARDS) + for test in iter_test_cases(conventions_test_shard(shard))] + self.assertEqual(sorted(sharded), sorted(discovered)) + self.assertEqual(len(sharded), len(set(sharded))) + self.assertTrue(all(len(list(iter_test_cases(conventions_test_shard(shard)))) > 0 + for shard in range(CONVENTIONS_TEST_SHARDS))) + class FunctionBodyTests(unittest.TestCase): def test_line_comments_preserve_following_statements(self): @@ -596,4 +629,16 @@ class RepositoryChecksTests(unittest.TestCase): if __name__ == "__main__": + if len(sys.argv) > 1 and sys.argv[1] == "--shard": + if len(sys.argv) != 3 or "/" not in sys.argv[2]: + print("usage: test_check_conventions_comments.py --shard INDEX/COUNT", file=sys.stderr) + raise SystemExit(2) + try: + shard_index, shard_count = (int(part) for part in sys.argv[2].split("/", 1)) + suite = conventions_test_shard(shard_index, shard_count) + except ValueError as error: + print(f"invalid shard: {error}", file=sys.stderr) + raise SystemExit(2) + result = unittest.TextTestRunner().run(suite) + raise SystemExit(0 if result.wasSuccessful() else 1) unittest.main()