Test data generators: add --list-outdated option As part of a long-term unification effort of generation scripts, add an option for test generators to list oudated targets without writing to files. This corresponds to functionality that the new generate_files_helper module offers. Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/scripts/mbedtls_framework/test_case.py b/scripts/mbedtls_framework/test_case.py index 58e75a1..a4f81ce 100644 --- a/scripts/mbedtls_framework/test_case.py +++ b/scripts/mbedtls_framework/test_case.py
@@ -127,6 +127,18 @@ out.write(prefix + self.function + ':' + ':'.join(self.arguments) + '\n') +def write_data_stream(out, + test_cases: Iterable[TestCase], + caller: Optional[str] = None) -> None: + """Write the test cases to the specified output stream.""" + if caller is None: + caller = os.path.basename(sys.argv[0]) + out.write('# Automatically generated by {}. Do not edit!\n' + .format(caller)) + for tc in test_cases: + tc.write(out) + out.write('\n# End of automatically generated file.\n') + def write_data_file(filename: str, test_cases: Iterable[TestCase], caller: Optional[str] = None) -> None: @@ -134,15 +146,9 @@ If the file already exists, it is overwritten. """ - if caller is None: - caller = os.path.basename(sys.argv[0]) tempfile = filename + '.new' with open(tempfile, 'w') as out: - out.write('# Automatically generated by {}. Do not edit!\n' - .format(caller)) - for tc in test_cases: - tc.write(out) - out.write('\n# End of automatically generated file.\n') + write_data_stream(out, test_cases, caller) os.replace(tempfile, filename) def psa_or_3_6_feature_macro(psa_name: str,
diff --git a/scripts/mbedtls_framework/test_data_generation.py b/scripts/mbedtls_framework/test_data_generation.py index a84f7dd..959fc15 100644 --- a/scripts/mbedtls_framework/test_data_generation.py +++ b/scripts/mbedtls_framework/test_data_generation.py
@@ -11,6 +11,7 @@ # import argparse +import io import os import posixpath import re @@ -139,6 +140,11 @@ class TestGenerator: """Generate test cases and write to data files.""" + + # Note that targets whose names contain 'test_format' have their content + # validated by `abi_check.py`. + targets = {} # type: Dict[str, Callable[..., Iterable[test_case.TestCase]]] + def __init__(self, options) -> None: self.test_suite_directory = options.directory # Update `targets` with an entry for each child class of BaseTarget. @@ -163,10 +169,6 @@ filename = self.filename_for(basename) test_case.write_data_file(filename, test_cases) - # Note that targets whose names contain 'test_format' have their content - # validated by `abi_check.py`. - targets = {} # type: Dict[str, Callable[..., Iterable[test_case.TestCase]]] - def generate_target(self, name: str, *target_args) -> None: """Generate cases and write to data file for a target. @@ -176,6 +178,22 @@ test_cases = self.targets[name](*target_args) self.write_test_data_file(name, test_cases) + def is_up_to_date(self, target) -> bool: + """Check if the given target already has the expected content.""" + filename = self.filename_for(target) + if not os.path.exists(filename): + return False + test_cases = self.targets[target]() + out = io.StringIO() + test_case.write_data_stream(out, test_cases) + out.seek(0) + new_content = out.read() + out.close() + with open(filename) as current_file: + old_content = current_file.read() + return new_content == old_content + + def main(args, description: str, generator_class: Type[TestGenerator] = TestGenerator): """Command line entry point.""" parser = argparse.ArgumentParser(description=description) @@ -183,6 +201,9 @@ help='List available targets and exit') parser.add_argument('--list-for-cmake', action='store_true', help='Print \';\'-separated list of available targets and exit') + parser.add_argument('--list-outdated', action='store_true', + help=('List outdated targets and exit ' + '(succeeds even if there are outdated or missing targets)')) # If specified explicitly, this option may be a path relative to the # current directory when the script is invoked. The default value # is relative to the mbedtls root, which we don't know yet. So we @@ -221,4 +242,8 @@ else: options.targets = sorted(generator.targets) for target in options.targets: - generator.generate_target(target) + if options.list_outdated: + if not generator.is_up_to_date(target): + print(generator.filename_for(target)) + else: + generator.generate_target(target)