mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-04-19 01:04:04 +03:00
Allow "skipping" a test case, meaning that the test case is generated commented out. This is useful when systematically generating test cases according to certain rules, where some generated tests cannot be executed but we still want them to be visible when auditing the generation output. Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
116 lines
3.8 KiB
Python
116 lines
3.8 KiB
Python
"""Library for constructing an Mbed TLS test case.
|
|
"""
|
|
|
|
# Copyright The Mbed TLS Contributors
|
|
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
|
#
|
|
|
|
import binascii
|
|
import os
|
|
import sys
|
|
from typing import Iterable, List, Optional
|
|
|
|
from . import typing_util
|
|
|
|
def hex_string(data: bytes) -> str:
|
|
return '"' + binascii.hexlify(data).decode('ascii') + '"'
|
|
|
|
|
|
class MissingDescription(Exception):
|
|
pass
|
|
|
|
class MissingFunction(Exception):
|
|
pass
|
|
|
|
class TestCase:
|
|
"""An Mbed TLS test case."""
|
|
|
|
def __init__(self, description: Optional[str] = None):
|
|
self.comments = [] #type: List[str]
|
|
self.description = description #type: Optional[str]
|
|
self.dependencies = [] #type: List[str]
|
|
self.function = None #type: Optional[str]
|
|
self.arguments = [] #type: List[str]
|
|
self.skip_reason = ''
|
|
|
|
def add_comment(self, *lines: str) -> None:
|
|
self.comments += lines
|
|
|
|
def set_description(self, description: str) -> None:
|
|
self.description = description
|
|
|
|
def set_dependencies(self, dependencies: List[str]) -> None:
|
|
self.dependencies = dependencies
|
|
|
|
def set_function(self, function: str) -> None:
|
|
self.function = function
|
|
|
|
def set_arguments(self, arguments: List[str]) -> None:
|
|
self.arguments = arguments
|
|
|
|
def skip_because(self, reason: str) -> None:
|
|
"""Skip this test case.
|
|
|
|
It will be included in the output, but commented out.
|
|
|
|
This is intended for test cases that are obtained from a
|
|
systematic enumeration, but that have dependencies that cannot
|
|
be fulfilled. Since we don't want to have test cases that are
|
|
never executed, we arrange not to have actual test cases. But
|
|
we do include comments to make it easier to understand the output
|
|
of test case generation.
|
|
|
|
reason must be a non-empty string explaining to humans why this
|
|
test case is skipped.
|
|
"""
|
|
self.skip_reason = reason
|
|
|
|
def check_completeness(self) -> None:
|
|
if self.description is None:
|
|
raise MissingDescription
|
|
if self.function is None:
|
|
raise MissingFunction
|
|
|
|
def write(self, out: typing_util.Writable) -> None:
|
|
"""Write the .data file paragraph for this test case.
|
|
|
|
The output starts and ends with a single newline character. If the
|
|
surrounding code writes lines (consisting of non-newline characters
|
|
and a final newline), you will end up with a blank line before, but
|
|
not after the test case.
|
|
"""
|
|
self.check_completeness()
|
|
assert self.description is not None # guide mypy
|
|
assert self.function is not None # guide mypy
|
|
out.write('\n')
|
|
for line in self.comments:
|
|
out.write('# ' + line + '\n')
|
|
prefix = ''
|
|
if self.skip_reason:
|
|
prefix = '## '
|
|
out.write('## # skipped because: ' + self.skip_reason + '\n')
|
|
out.write(prefix + self.description + '\n')
|
|
if self.dependencies:
|
|
out.write(prefix + 'depends_on:' +
|
|
':'.join(self.dependencies) + '\n')
|
|
out.write(prefix + self.function + ':' +
|
|
':'.join(self.arguments) + '\n')
|
|
|
|
def write_data_file(filename: str,
|
|
test_cases: Iterable[TestCase],
|
|
caller: Optional[str] = None) -> None:
|
|
"""Write the test cases to the specified file.
|
|
|
|
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')
|
|
os.replace(tempfile, filename)
|