1"""Library for constructing an Mbed TLS test case. 2""" 3 4# Copyright The Mbed TLS Contributors 5# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6# 7 8import binascii 9import os 10import sys 11from typing import Iterable, List, Optional 12 13from . import typing_util 14 15def hex_string(data: bytes) -> str: 16 return '"' + binascii.hexlify(data).decode('ascii') + '"' 17 18 19class MissingDescription(Exception): 20 pass 21 22class MissingFunction(Exception): 23 pass 24 25class TestCase: 26 """An Mbed TLS test case.""" 27 28 def __init__(self, description: Optional[str] = None): 29 self.comments = [] #type: List[str] 30 self.description = description #type: Optional[str] 31 self.dependencies = [] #type: List[str] 32 self.function = None #type: Optional[str] 33 self.arguments = [] #type: List[str] 34 35 def add_comment(self, *lines: str) -> None: 36 self.comments += lines 37 38 def set_description(self, description: str) -> None: 39 self.description = description 40 41 def set_dependencies(self, dependencies: List[str]) -> None: 42 self.dependencies = dependencies 43 44 def set_function(self, function: str) -> None: 45 self.function = function 46 47 def set_arguments(self, arguments: List[str]) -> None: 48 self.arguments = arguments 49 50 def check_completeness(self) -> None: 51 if self.description is None: 52 raise MissingDescription 53 if self.function is None: 54 raise MissingFunction 55 56 def write(self, out: typing_util.Writable) -> None: 57 """Write the .data file paragraph for this test case. 58 59 The output starts and ends with a single newline character. If the 60 surrounding code writes lines (consisting of non-newline characters 61 and a final newline), you will end up with a blank line before, but 62 not after the test case. 63 """ 64 self.check_completeness() 65 assert self.description is not None # guide mypy 66 assert self.function is not None # guide mypy 67 out.write('\n') 68 for line in self.comments: 69 out.write('# ' + line + '\n') 70 out.write(self.description + '\n') 71 if self.dependencies: 72 out.write('depends_on:' + ':'.join(self.dependencies) + '\n') 73 out.write(self.function + ':' + ':'.join(self.arguments) + '\n') 74 75def write_data_file(filename: str, 76 test_cases: Iterable[TestCase], 77 caller: Optional[str] = None) -> None: 78 """Write the test cases to the specified file. 79 80 If the file already exists, it is overwritten. 81 """ 82 if caller is None: 83 caller = os.path.basename(sys.argv[0]) 84 tempfile = filename + '.new' 85 with open(tempfile, 'w') as out: 86 out.write('# Automatically generated by {}. Do not edit!\n' 87 .format(caller)) 88 for tc in test_cases: 89 tc.write(out) 90 out.write('\n# End of automatically generated file.\n') 91 os.replace(tempfile, filename) 92