Gilles Peskine | 693611e | 2024-06-11 19:32:22 +0200 | [diff] [blame^] | 1 | #!/usr/bin/env python3 |
| 2 | """Generate test data for configuration reporting. |
| 3 | """ |
| 4 | |
| 5 | # Copyright The Mbed TLS Contributors |
| 6 | # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
| 7 | |
| 8 | import re |
| 9 | import sys |
| 10 | from typing import Iterable, Iterator, List, Optional, Tuple |
| 11 | |
| 12 | import project_scripts # pylint: disable=unused-import |
| 13 | import config |
| 14 | from mbedtls_framework import test_case |
| 15 | from mbedtls_framework import test_data_generation |
| 16 | |
| 17 | |
| 18 | def single_option_case(setting: config.Setting, when_on: bool, |
| 19 | dependencies: List[str], |
| 20 | note: Optional[str]) -> test_case.TestCase: |
| 21 | """Construct a test case for a boolean setting. |
| 22 | |
| 23 | This test case passes if the setting and its dependencies are enabled, |
| 24 | and is skipped otherwise. |
| 25 | |
| 26 | * setting: the setting to be tested. |
| 27 | * when_on: True to test with the setting enabled, or False to test |
| 28 | with the setting disabled. |
| 29 | * dependencies: extra dependencies for the test case. |
| 30 | * note: a note to add after the option name in the test description. |
| 31 | This is generally a summary of dependencies, and is generally empty |
| 32 | if the given setting is only tested once. |
| 33 | """ |
| 34 | base = setting.name if when_on else '!' + setting.name |
| 35 | tc = test_case.TestCase() |
| 36 | tc.set_function('pass') |
| 37 | description_suffix = ' (' + note + ')' if note else '' |
| 38 | tc.set_description('Config: ' + base + description_suffix) |
| 39 | tc.set_dependencies([base] + dependencies) |
| 40 | return tc |
| 41 | |
| 42 | |
| 43 | def conditions_for_option(cfg: config.Config, |
| 44 | setting: config.Setting |
| 45 | ) -> Iterator[Tuple[List[str], str]]: |
| 46 | """Enumerate the conditions under which to test the given setting. |
| 47 | |
| 48 | * cfg: all configuration options. |
| 49 | * setting: the setting to be tested. |
| 50 | |
| 51 | Generate a stream of conditions, i.e. extra dependencies to test with |
| 52 | together with a human-readable explanation of each dependency. Some |
| 53 | typical cases: |
| 54 | |
| 55 | * By default, generate a one-element stream with no extra dependencies. |
| 56 | * If the setting is ignored unless some other option is enabled, generate |
| 57 | a one-element stream with that other option as an extra dependency. |
| 58 | * If the setting is known to interact with some other option, generate |
| 59 | a stream with one element where this option is on and one where it's off. |
| 60 | * To skip the setting altogether, generate an empty stream. |
| 61 | """ |
| 62 | name = setting.name |
| 63 | if name.endswith('_ALT') and not config.is_seamless_alt(name): |
| 64 | # We don't test alt implementations, except (most) platform alts |
| 65 | return |
| 66 | yield [], '' |
| 67 | |
| 68 | |
| 69 | def enumerate_boolean_option_cases(cfg: config.Config |
| 70 | ) -> Iterable[test_case.TestCase]: |
| 71 | """Emit test cases for all boolean options.""" |
| 72 | for name in sorted(cfg.settings.keys()): |
| 73 | setting = cfg.settings[name] |
| 74 | if not name.startswith('PSA_WANT_') and setting.value: |
| 75 | continue # non-boolean setting |
| 76 | for when_on in True, False: |
| 77 | for deps, note in conditions_for_option(cfg, setting): |
| 78 | yield single_option_case(setting, when_on, deps, note) |
| 79 | |
| 80 | |
| 81 | |
| 82 | class ConfigTestGenerator(test_data_generation.TestGenerator): |
| 83 | """Generate test cases for configuration reporting.""" |
| 84 | |
| 85 | def __init__(self, options): |
| 86 | self.mbedtls_config = config.ConfigFile() |
| 87 | self.targets['test_suite_config.mbedtls_boolean'] = \ |
| 88 | lambda: enumerate_boolean_option_cases(self.mbedtls_config) |
| 89 | self.psa_config = config.ConfigFile('include/psa/crypto_config.h') |
| 90 | self.targets['test_suite_config.psa_boolean'] = \ |
| 91 | lambda: enumerate_boolean_option_cases(self.psa_config) |
| 92 | super().__init__(options) |
| 93 | |
| 94 | |
| 95 | if __name__ == '__main__': |
| 96 | test_data_generation.main(sys.argv[1:], __doc__, ConfigTestGenerator) |