From da9e3eec651797301a41f7a7ab5f47241b69dece Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 10 Apr 2020 17:25:13 -0400 Subject: [PATCH] Add test for consistent random ordering --- projects/CMakeLists.txt | 2 + projects/TestScripts/testRandomOrder.py | 53 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100755 projects/TestScripts/testRandomOrder.py diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index 0aafc1780d..08badb809a 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -451,6 +451,8 @@ set_tests_properties(TestsInFile::InvalidTestNames-1 PROPERTIES PASS_REGULAR_EXP add_test(NAME TestsInFile::InvalidTestNames-2 COMMAND $ "-f ${CATCH_DIR}/projects/SelfTest/Misc/invalid-test-names.input") set_tests_properties(TestsInFile::InvalidTestNames-2 PROPERTIES PASS_REGULAR_EXPRESSION "No tests ran") +add_test(NAME RandomTestOrdering COMMAND ${PYTHON_EXECUTABLE} + ${CATCH_DIR}/projects/TestScripts/testRandomOrder.py $) if (CATCH_USE_VALGRIND) add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $) diff --git a/projects/TestScripts/testRandomOrder.py b/projects/TestScripts/testRandomOrder.py new file mode 100755 index 0000000000..68f53f19af --- /dev/null +++ b/projects/TestScripts/testRandomOrder.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +import subprocess +import sys + +def list_tests(self_test_exe, tags, rng_seed): + cmd = [self_test_exe, '--list-test-names-only', '--order', 'rand', + '--rng-seed', str(rng_seed)] + tags_arg = ','.join('[{}]'.format(t) for t in tags) + if tags_arg: + cmd.append(tags_arg + '~[.]') + process = subprocess.Popen( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = process.communicate() + if stderr: + raise RuntimeError("Unexpected error output:\n" + process.stderr) + result = stdout.split(b'\n') + result = [s for s in result if s] + if len(result) < 2: + raise RuntimeError("Unexpectedly few tests listed (got {})".format( + len(result))) + return result + +def check_is_sublist_of(shorter, longer): + assert len(shorter) < len(longer) + assert len(set(longer)) == len(longer) + + indexes_in_longer = {s: i for i, s in enumerate(longer)} + for s1, s2 in zip(shorter, shorter[1:]): + assert indexes_in_longer[s1] < indexes_in_longer[s2], ( + '{} comes before {} in longer list.\n' + 'Longer: {}\nShorter: {}'.format(s2, s1, longer, shorter)) + +def main(): + self_test_exe, = sys.argv[1:] + + list_one_tag = list_tests(self_test_exe, ['generators'], 1) + list_two_tags = list_tests(self_test_exe, ['generators', 'matchers'], 1) + list_all = list_tests(self_test_exe, [], 1) + + # First, verify that restricting to a subset yields the same order + check_is_sublist_of(list_two_tags, list_all) + check_is_sublist_of(list_one_tag, list_two_tags) + + # Second, verify that different seeds yield different orders + num_seeds = 100 + seeds = range(1, num_seeds + 1) # Avoid zero since that's special + lists = {tuple(list_tests(self_test_exe, [], seed)) for seed in seeds} + assert len(lists) == num_seeds, ( + 'Got {} distict lists from {} seeds'.format(len(lists), num_seeds)) + +if __name__ == '__main__': + sys.exit(main())