1*62c56f98SSadaf Ebrahimi#!/usr/bin/env python3 2*62c56f98SSadaf Ebrahimi"""Generate test data for bignum functions. 3*62c56f98SSadaf Ebrahimi 4*62c56f98SSadaf EbrahimiWith no arguments, generate all test data. With non-option arguments, 5*62c56f98SSadaf Ebrahimigenerate only the specified files. 6*62c56f98SSadaf Ebrahimi 7*62c56f98SSadaf EbrahimiClass structure: 8*62c56f98SSadaf Ebrahimi 9*62c56f98SSadaf EbrahimiChild classes of test_data_generation.BaseTarget (file targets) represent an output 10*62c56f98SSadaf Ebrahimifile. These indicate where test cases will be written to, for all subclasses of 11*62c56f98SSadaf Ebrahimithis target. Multiple file targets should not reuse a `target_basename`. 12*62c56f98SSadaf Ebrahimi 13*62c56f98SSadaf EbrahimiEach subclass derived from a file target can either be: 14*62c56f98SSadaf Ebrahimi - A concrete class, representing a test function, which generates test cases. 15*62c56f98SSadaf Ebrahimi - An abstract class containing shared methods and attributes, not associated 16*62c56f98SSadaf Ebrahimi with a test function. An example is BignumOperation, which provides 17*62c56f98SSadaf Ebrahimi common features used for bignum binary operations. 18*62c56f98SSadaf Ebrahimi 19*62c56f98SSadaf EbrahimiBoth concrete and abstract subclasses can be derived from, to implement 20*62c56f98SSadaf Ebrahimiadditional test cases (see BignumCmp and BignumCmpAbs for examples of deriving 21*62c56f98SSadaf Ebrahimifrom abstract and concrete classes). 22*62c56f98SSadaf Ebrahimi 23*62c56f98SSadaf Ebrahimi 24*62c56f98SSadaf EbrahimiAdding test case generation for a function: 25*62c56f98SSadaf Ebrahimi 26*62c56f98SSadaf EbrahimiA subclass representing the test function should be added, deriving from a 27*62c56f98SSadaf Ebrahimifile target such as BignumTarget. This test class must set/implement the 28*62c56f98SSadaf Ebrahimifollowing: 29*62c56f98SSadaf Ebrahimi - test_function: the function name from the associated .function file. 30*62c56f98SSadaf Ebrahimi - test_name: a descriptive name or brief summary to refer to the test 31*62c56f98SSadaf Ebrahimi function. 32*62c56f98SSadaf Ebrahimi - arguments(): a method to generate the list of arguments required for the 33*62c56f98SSadaf Ebrahimi test_function. 34*62c56f98SSadaf Ebrahimi - generate_function_tests(): a method to generate TestCases for the function. 35*62c56f98SSadaf Ebrahimi This should create instances of the class with required input data, and 36*62c56f98SSadaf Ebrahimi call `.create_test_case()` to yield the TestCase. 37*62c56f98SSadaf Ebrahimi 38*62c56f98SSadaf EbrahimiAdditional details and other attributes/methods are given in the documentation 39*62c56f98SSadaf Ebrahimiof BaseTarget in test_data_generation.py. 40*62c56f98SSadaf Ebrahimi""" 41*62c56f98SSadaf Ebrahimi 42*62c56f98SSadaf Ebrahimi# Copyright The Mbed TLS Contributors 43*62c56f98SSadaf Ebrahimi# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 44*62c56f98SSadaf Ebrahimi 45*62c56f98SSadaf Ebrahimiimport sys 46*62c56f98SSadaf Ebrahimi 47*62c56f98SSadaf Ebrahimifrom abc import ABCMeta 48*62c56f98SSadaf Ebrahimifrom typing import List 49*62c56f98SSadaf Ebrahimi 50*62c56f98SSadaf Ebrahimiimport scripts_path # pylint: disable=unused-import 51*62c56f98SSadaf Ebrahimifrom mbedtls_dev import test_data_generation 52*62c56f98SSadaf Ebrahimifrom mbedtls_dev import bignum_common 53*62c56f98SSadaf Ebrahimi# Import modules containing additional test classes 54*62c56f98SSadaf Ebrahimi# Test function classes in these modules will be registered by 55*62c56f98SSadaf Ebrahimi# the framework 56*62c56f98SSadaf Ebrahimifrom mbedtls_dev import bignum_core, bignum_mod_raw, bignum_mod # pylint: disable=unused-import 57*62c56f98SSadaf Ebrahimi 58*62c56f98SSadaf Ebrahimiclass BignumTarget(test_data_generation.BaseTarget): 59*62c56f98SSadaf Ebrahimi #pylint: disable=too-few-public-methods 60*62c56f98SSadaf Ebrahimi """Target for bignum (legacy) test case generation.""" 61*62c56f98SSadaf Ebrahimi target_basename = 'test_suite_bignum.generated' 62*62c56f98SSadaf Ebrahimi 63*62c56f98SSadaf Ebrahimi 64*62c56f98SSadaf Ebrahimiclass BignumOperation(bignum_common.OperationCommon, BignumTarget, 65*62c56f98SSadaf Ebrahimi metaclass=ABCMeta): 66*62c56f98SSadaf Ebrahimi #pylint: disable=abstract-method 67*62c56f98SSadaf Ebrahimi """Common features for bignum operations in legacy tests.""" 68*62c56f98SSadaf Ebrahimi unique_combinations_only = True 69*62c56f98SSadaf Ebrahimi input_values = [ 70*62c56f98SSadaf Ebrahimi "", "0", "-", "-0", 71*62c56f98SSadaf Ebrahimi "7b", "-7b", 72*62c56f98SSadaf Ebrahimi "0000000000000000123", "-0000000000000000123", 73*62c56f98SSadaf Ebrahimi "1230000000000000000", "-1230000000000000000" 74*62c56f98SSadaf Ebrahimi ] 75*62c56f98SSadaf Ebrahimi 76*62c56f98SSadaf Ebrahimi def description_suffix(self) -> str: 77*62c56f98SSadaf Ebrahimi #pylint: disable=no-self-use # derived classes need self 78*62c56f98SSadaf Ebrahimi """Text to add at the end of the test case description.""" 79*62c56f98SSadaf Ebrahimi return "" 80*62c56f98SSadaf Ebrahimi 81*62c56f98SSadaf Ebrahimi def description(self) -> str: 82*62c56f98SSadaf Ebrahimi """Generate a description for the test case. 83*62c56f98SSadaf Ebrahimi 84*62c56f98SSadaf Ebrahimi If not set, case_description uses the form A `symbol` B, where symbol 85*62c56f98SSadaf Ebrahimi is used to represent the operation. Descriptions of each value are 86*62c56f98SSadaf Ebrahimi generated to provide some context to the test case. 87*62c56f98SSadaf Ebrahimi """ 88*62c56f98SSadaf Ebrahimi if not self.case_description: 89*62c56f98SSadaf Ebrahimi self.case_description = "{} {} {}".format( 90*62c56f98SSadaf Ebrahimi self.value_description(self.arg_a), 91*62c56f98SSadaf Ebrahimi self.symbol, 92*62c56f98SSadaf Ebrahimi self.value_description(self.arg_b) 93*62c56f98SSadaf Ebrahimi ) 94*62c56f98SSadaf Ebrahimi description_suffix = self.description_suffix() 95*62c56f98SSadaf Ebrahimi if description_suffix: 96*62c56f98SSadaf Ebrahimi self.case_description += " " + description_suffix 97*62c56f98SSadaf Ebrahimi return super().description() 98*62c56f98SSadaf Ebrahimi 99*62c56f98SSadaf Ebrahimi @staticmethod 100*62c56f98SSadaf Ebrahimi def value_description(val) -> str: 101*62c56f98SSadaf Ebrahimi """Generate a description of the argument val. 102*62c56f98SSadaf Ebrahimi 103*62c56f98SSadaf Ebrahimi This produces a simple description of the value, which is used in test 104*62c56f98SSadaf Ebrahimi case naming to add context. 105*62c56f98SSadaf Ebrahimi """ 106*62c56f98SSadaf Ebrahimi if val == "": 107*62c56f98SSadaf Ebrahimi return "0 (null)" 108*62c56f98SSadaf Ebrahimi if val == "-": 109*62c56f98SSadaf Ebrahimi return "negative 0 (null)" 110*62c56f98SSadaf Ebrahimi if val == "0": 111*62c56f98SSadaf Ebrahimi return "0 (1 limb)" 112*62c56f98SSadaf Ebrahimi 113*62c56f98SSadaf Ebrahimi if val[0] == "-": 114*62c56f98SSadaf Ebrahimi tmp = "negative" 115*62c56f98SSadaf Ebrahimi val = val[1:] 116*62c56f98SSadaf Ebrahimi else: 117*62c56f98SSadaf Ebrahimi tmp = "positive" 118*62c56f98SSadaf Ebrahimi if val[0] == "0": 119*62c56f98SSadaf Ebrahimi tmp += " with leading zero limb" 120*62c56f98SSadaf Ebrahimi elif len(val) > 10: 121*62c56f98SSadaf Ebrahimi tmp = "large " + tmp 122*62c56f98SSadaf Ebrahimi return tmp 123*62c56f98SSadaf Ebrahimi 124*62c56f98SSadaf Ebrahimi 125*62c56f98SSadaf Ebrahimiclass BignumCmp(BignumOperation): 126*62c56f98SSadaf Ebrahimi """Test cases for bignum value comparison.""" 127*62c56f98SSadaf Ebrahimi count = 0 128*62c56f98SSadaf Ebrahimi test_function = "mpi_cmp_mpi" 129*62c56f98SSadaf Ebrahimi test_name = "MPI compare" 130*62c56f98SSadaf Ebrahimi input_cases = [ 131*62c56f98SSadaf Ebrahimi ("-2", "-3"), 132*62c56f98SSadaf Ebrahimi ("-2", "-2"), 133*62c56f98SSadaf Ebrahimi ("2b4", "2b5"), 134*62c56f98SSadaf Ebrahimi ("2b5", "2b6") 135*62c56f98SSadaf Ebrahimi ] 136*62c56f98SSadaf Ebrahimi 137*62c56f98SSadaf Ebrahimi def __init__(self, val_a, val_b) -> None: 138*62c56f98SSadaf Ebrahimi super().__init__(val_a, val_b) 139*62c56f98SSadaf Ebrahimi self._result = int(self.int_a > self.int_b) - int(self.int_a < self.int_b) 140*62c56f98SSadaf Ebrahimi self.symbol = ["<", "==", ">"][self._result + 1] 141*62c56f98SSadaf Ebrahimi 142*62c56f98SSadaf Ebrahimi def result(self) -> List[str]: 143*62c56f98SSadaf Ebrahimi return [str(self._result)] 144*62c56f98SSadaf Ebrahimi 145*62c56f98SSadaf Ebrahimi 146*62c56f98SSadaf Ebrahimiclass BignumCmpAbs(BignumCmp): 147*62c56f98SSadaf Ebrahimi """Test cases for absolute bignum value comparison.""" 148*62c56f98SSadaf Ebrahimi count = 0 149*62c56f98SSadaf Ebrahimi test_function = "mpi_cmp_abs" 150*62c56f98SSadaf Ebrahimi test_name = "MPI compare (abs)" 151*62c56f98SSadaf Ebrahimi 152*62c56f98SSadaf Ebrahimi def __init__(self, val_a, val_b) -> None: 153*62c56f98SSadaf Ebrahimi super().__init__(val_a.strip("-"), val_b.strip("-")) 154*62c56f98SSadaf Ebrahimi 155*62c56f98SSadaf Ebrahimi 156*62c56f98SSadaf Ebrahimiclass BignumAdd(BignumOperation): 157*62c56f98SSadaf Ebrahimi """Test cases for bignum value addition.""" 158*62c56f98SSadaf Ebrahimi count = 0 159*62c56f98SSadaf Ebrahimi symbol = "+" 160*62c56f98SSadaf Ebrahimi test_function = "mpi_add_mpi" 161*62c56f98SSadaf Ebrahimi test_name = "MPI add" 162*62c56f98SSadaf Ebrahimi input_cases = bignum_common.combination_pairs( 163*62c56f98SSadaf Ebrahimi [ 164*62c56f98SSadaf Ebrahimi "1c67967269c6", "9cde3", 165*62c56f98SSadaf Ebrahimi "-1c67967269c6", "-9cde3", 166*62c56f98SSadaf Ebrahimi ] 167*62c56f98SSadaf Ebrahimi ) 168*62c56f98SSadaf Ebrahimi 169*62c56f98SSadaf Ebrahimi def __init__(self, val_a: str, val_b: str) -> None: 170*62c56f98SSadaf Ebrahimi super().__init__(val_a, val_b) 171*62c56f98SSadaf Ebrahimi self._result = self.int_a + self.int_b 172*62c56f98SSadaf Ebrahimi 173*62c56f98SSadaf Ebrahimi def description_suffix(self) -> str: 174*62c56f98SSadaf Ebrahimi if (self.int_a >= 0 and self.int_b >= 0): 175*62c56f98SSadaf Ebrahimi return "" # obviously positive result or 0 176*62c56f98SSadaf Ebrahimi if (self.int_a <= 0 and self.int_b <= 0): 177*62c56f98SSadaf Ebrahimi return "" # obviously negative result or 0 178*62c56f98SSadaf Ebrahimi # The sign of the result is not obvious, so indicate it 179*62c56f98SSadaf Ebrahimi return ", result{}0".format('>' if self._result > 0 else 180*62c56f98SSadaf Ebrahimi '<' if self._result < 0 else '=') 181*62c56f98SSadaf Ebrahimi 182*62c56f98SSadaf Ebrahimi def result(self) -> List[str]: 183*62c56f98SSadaf Ebrahimi return [bignum_common.quote_str("{:x}".format(self._result))] 184*62c56f98SSadaf Ebrahimi 185*62c56f98SSadaf Ebrahimiif __name__ == '__main__': 186*62c56f98SSadaf Ebrahimi # Use the section of the docstring relevant to the CLI as description 187*62c56f98SSadaf Ebrahimi test_data_generation.main(sys.argv[1:], "\n".join(__doc__.splitlines()[:4])) 188