Clean up not-implemented detection
Move hack_dependencies_not_implemented into a class to make the file
structure easier to understand and reduce the visibility of the
_implemented_dependencies cache. Rename it because it's no longer a
temporary hack (originally intended to work around the fact that not all
PSA_WANT symbols were implemented), it's now a way to detect test cases for
cryptographic mechanisms that are declared but not implemented.
Internal refactoring only. No behavior change.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/scripts/mbedtls_dev/psa_information.py b/scripts/mbedtls_dev/psa_information.py
index 0e68df0..6f9c738 100644
--- a/scripts/mbedtls_dev/psa_information.py
+++ b/scripts/mbedtls_dev/psa_information.py
@@ -6,7 +6,7 @@
import re
-from typing import Dict, FrozenSet, List, Optional, Set
+from typing import Dict, FrozenSet, Iterator, List, Optional, Set
from . import macro_collector
from . import test_case
@@ -54,30 +54,6 @@
used.difference_update(SYMBOLS_WITHOUT_DEPENDENCY)
return sorted(psa_want_symbol(name) for name in used)
-# Skip test cases for which the dependency symbols are not defined.
-# We assume that this means that a required mechanism is not implemented.
-# Note that if we erroneously skip generating test cases for
-# mechanisms that are not implemented, this should be caught
-# by the NOT_SUPPORTED test cases generated by generate_psa_tests.py
-# in test_suite_psa_crypto_not_supported and test_suite_psa_crypto_op_fail:
-# those emit negative tests, which will not be skipped here.
-def read_implemented_dependencies(filename: str) -> FrozenSet[str]:
- return frozenset(symbol
- for line in open(filename)
- for symbol in re.findall(r'\bPSA_WANT_\w+\b', line))
-_implemented_dependencies = None #type: Optional[FrozenSet[str]] #pylint: disable=invalid-name
-
-def hack_dependencies_not_implemented(dependencies: List[str]) -> None:
- global _implemented_dependencies #pylint: disable=global-statement,invalid-name
- if _implemented_dependencies is None:
- _implemented_dependencies = \
- read_implemented_dependencies('include/psa/crypto_config.h')
- _implemented_dependencies = _implemented_dependencies.union(
- read_implemented_dependencies('include/mbedtls/config_psa.h'))
- for dep in dependencies:
- if dep.startswith('PSA_WANT') and dep not in _implemented_dependencies:
- dependencies.append('DEPENDENCY_NOT_IMPLEMENTED_YET_' + dep)
- dependencies.sort()
class Information:
"""Gather information about PSA constructors."""
@@ -119,6 +95,47 @@
involved in a given test case.
"""
+ # Use a class variable to cache the set of implemented dependencies.
+ # Call read_implemented_dependencies() to fill the cache.
+ _implemented_dependencies = None #type: Optional[FrozenSet[str]]
+
+ DEPENDENCY_SYMBOL_RE = re.compile(r'\bPSA_WANT_\w+\b')
+ @classmethod
+ def _yield_implemented_dependencies(cls) -> Iterator[str]:
+ for filename in ['include/psa/crypto_config.h',
+ 'include/mbedtls/config_psa.h']:
+ with open(filename) as inp:
+ content = inp.read()
+ yield from cls.DEPENDENCY_SYMBOL_RE.findall(content)
+
+ @classmethod
+ def read_implemented_dependencies(cls) -> FrozenSet[str]:
+ if cls._implemented_dependencies is None:
+ cls._implemented_dependencies = \
+ frozenset(cls._yield_implemented_dependencies())
+ # Redundant return to reassure pylint (mypy is fine without it).
+ # Known issue: https://github.com/pylint-dev/pylint/issues/3045
+ return cls._implemented_dependencies
+ return cls._implemented_dependencies
+
+ # We skip test cases for which the dependency symbols are not defined.
+ # We assume that this means that a required mechanism is not implemented.
+ # Note that if we erroneously skip generating test cases for
+ # mechanisms that are not implemented, this should be caught
+ # by the NOT_SUPPORTED test cases generated by generate_psa_tests.py
+ # in test_suite_psa_crypto_not_supported and test_suite_psa_crypto_op_fail:
+ # those emit negative tests, which will not be skipped here.
+ def detect_not_implemented_dependencies(self) -> None:
+ """Detect dependencies that are not implemented."""
+ all_implemented_dependencies = self.read_implemented_dependencies()
+ not_implemented = set()
+ for dep in self.dependencies:
+ if (dep.startswith('PSA_WANT') and
+ dep not in all_implemented_dependencies):
+ not_implemented.add('DEPENDENCY_NOT_IMPLEMENTED_YET_' + dep)
+ self.dependencies = sorted(not_implemented) + self.dependencies
+ self.dependencies.sort()
+
def __init__(self) -> None:
super().__init__()
self.key_bits = None #type: Optional[int]
@@ -157,5 +174,5 @@
dependencies[i] = '!' + dependencies[i]
if self.key_bits is not None:
dependencies = finish_family_dependencies(dependencies, self.key_bits)
- hack_dependencies_not_implemented(dependencies)
- self.dependencies += dependencies
+ self.dependencies += sorted(dependencies)
+ self.detect_not_implemented_dependencies()