Fix style errors reported by pylint

This commit is contained in:
Azim Khan 2018-07-03 11:57:54 +01:00 committed by Mohammad Azim Khan
parent aee05bbe70
commit b31aa44e16
3 changed files with 883 additions and 641 deletions

View file

@ -16,7 +16,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# This file is part of mbed TLS (https://tls.mbed.org) # This file is part of Mbed TLS (https://tls.mbed.org)
""" """
This script is a key part of Mbed TLS test suites framework. For This script is a key part of Mbed TLS test suites framework. For
@ -29,7 +29,7 @@ Mbed TLS test suites:
Scope: Scope:
------ ------
The test suites focus on unit testing the crypto primitives and also The test suites focus on unit testing the crypto primitives and also
include x509 parser tests. Tests can be added to test any MBED TLS include x509 parser tests. Tests can be added to test any Mbed TLS
module. However, the framework is not capable of testing SSL module. However, the framework is not capable of testing SSL
protocol, since that requires full stack execution and that is best protocol, since that requires full stack execution and that is best
tested as part of the system test. tested as part of the system test.
@ -59,7 +59,8 @@ as an expression. Following is an example test definition:
X509 CRL Unsupported critical extension (issuingDistributionPoint) X509 CRL Unsupported critical extension (issuingDistributionPoint)
depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
mbedtls_x509_crl_parse:"data_files/crl-idp.pem":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG mbedtls_x509_crl_parse:"data_files/crl-idp.pem":\
MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
Test functions: Test functions:
--------------- ---------------
@ -170,17 +171,17 @@ import sys
import argparse import argparse
BEGIN_HEADER_REGEX = '/\*\s*BEGIN_HEADER\s*\*/' BEGIN_HEADER_REGEX = r'/\*\s*BEGIN_HEADER\s*\*/'
END_HEADER_REGEX = '/\*\s*END_HEADER\s*\*/' END_HEADER_REGEX = r'/\*\s*END_HEADER\s*\*/'
BEGIN_SUITE_HELPERS_REGEX = '/\*\s*BEGIN_SUITE_HELPERS\s*\*/' BEGIN_SUITE_HELPERS_REGEX = r'/\*\s*BEGIN_SUITE_HELPERS\s*\*/'
END_SUITE_HELPERS_REGEX = '/\*\s*END_SUITE_HELPERS\s*\*/' END_SUITE_HELPERS_REGEX = r'/\*\s*END_SUITE_HELPERS\s*\*/'
BEGIN_DEP_REGEX = 'BEGIN_DEPENDENCIES' BEGIN_DEP_REGEX = r'BEGIN_DEPENDENCIES'
END_DEP_REGEX = 'END_DEPENDENCIES' END_DEP_REGEX = r'END_DEPENDENCIES'
BEGIN_CASE_REGEX = '/\*\s*BEGIN_CASE\s*(.*?)\s*\*/' BEGIN_CASE_REGEX = r'/\*\s*BEGIN_CASE\s*(.*?)\s*\*/'
END_CASE_REGEX = '/\*\s*END_CASE\s*\*/' END_CASE_REGEX = r'/\*\s*END_CASE\s*\*/'
class GeneratorInputError(Exception): class GeneratorInputError(Exception):
@ -192,7 +193,7 @@ class GeneratorInputError(Exception):
pass pass
class FileWrapper(io.FileIO): class FileWrapper(io.FileIO, object):
""" """
This class extends built-in io.FileIO class with attribute line_no, This class extends built-in io.FileIO class with attribute line_no,
that indicates line number for the line that is read. that indicates line number for the line that is read.
@ -205,9 +206,9 @@ class FileWrapper(io.FileIO):
:param file_name: File path to open. :param file_name: File path to open.
""" """
super(FileWrapper, self).__init__(file_name, 'r') super(FileWrapper, self).__init__(file_name, 'r')
self.line_no = 0 self._line_no = 0
def __next__(self): def next(self):
""" """
Python 2 iterator method. This method overrides base class's Python 2 iterator method. This method overrides base class's
next method and extends the next method to count the line next method and extends the next method to count the line
@ -220,23 +221,31 @@ class FileWrapper(io.FileIO):
""" """
parent = super(FileWrapper, self) parent = super(FileWrapper, self)
if hasattr(parent, '__next__'): if hasattr(parent, '__next__'):
line = parent.__next__() # Python 3 line = parent.__next__() # Python 3
else: else:
line = parent.next() # Python 2 line = parent.next() # Python 2
if line: if line is not None:
self.line_no += 1 self._line_no += 1
# Convert byte array to string with correct encoding and # Convert byte array to string with correct encoding and
# strip any whitespaces added in the decoding process. # strip any whitespaces added in the decoding process.
return line.decode(sys.getdefaultencoding()).strip() + "\n" return line.decode(sys.getdefaultencoding()).strip() + "\n"
return None return None
# Python 3 iterator method # Python 3 iterator method
next = __next__ __next__ = next
def get_line_no(self):
"""
Gives current line number.
"""
return self._line_no
line_no = property(get_line_no)
def split_dep(dep): def split_dep(dep):
""" """
Split NOT character '!' from dependency. Used by gen_deps() Split NOT character '!' from dependency. Used by gen_dependencies()
:param dep: Dependency list :param dep: Dependency list
:return: string tuple. Ex: ('!', MACRO) for !MACRO and ('', MACRO) for :return: string tuple. Ex: ('!', MACRO) for !MACRO and ('', MACRO) for
@ -245,7 +254,7 @@ def split_dep(dep):
return ('!', dep[1:]) if dep[0] == '!' else ('', dep) return ('!', dep[1:]) if dep[0] == '!' else ('', dep)
def gen_deps(deps): def gen_dependencies(dependencies):
""" """
Test suite data and functions specifies compile time dependencies. Test suite data and functions specifies compile time dependencies.
This function generates C preprocessor code from the input This function generates C preprocessor code from the input
@ -256,36 +265,39 @@ def gen_deps(deps):
function split_dep() and proper preprocessor check is generated function split_dep() and proper preprocessor check is generated
accordingly. accordingly.
:param deps: List of dependencies. :param dependencies: List of dependencies.
:return: if defined and endif code with macro annotations for :return: if defined and endif code with macro annotations for
readability. readability.
""" """
dep_start = ''.join(['#if %sdefined(%s)\n' % split_dep(x) for x in deps]) dep_start = ''.join(['#if %sdefined(%s)\n' % (x, y) for x, y in
dep_end = ''.join(['#endif /* %s */\n' % x for x in reversed(deps)]) map(split_dep, dependencies)])
dep_end = ''.join(['#endif /* %s */\n' %
x for x in reversed(dependencies)])
return dep_start, dep_end return dep_start, dep_end
def gen_deps_one_line(deps): def gen_dependencies_one_line(dependencies):
""" """
Similar to gen_deps() but generates dependency checks in one line. Similar to gen_dependencies() but generates dependency checks in one line.
Useful for generating code with #else block. Useful for generating code with #else block.
:param deps: List of dependencies. :param dependencies: List of dependencies.
:return: ifdef code :return: Preprocessor check code
""" """
defines = '#if ' if len(deps) else '' defines = '#if ' if dependencies else ''
defines += ' && '.join(['%sdefined(%s)' % split_dep(x) for x in deps]) defines += ' && '.join(['%sdefined(%s)' % (x, y) for x, y in map(
split_dep, dependencies)])
return defines return defines
def gen_function_wrapper(name, locals, args_dispatch): def gen_function_wrapper(name, local_vars, args_dispatch):
""" """
Creates test function wrapper code. A wrapper has the code to Creates test function wrapper code. A wrapper has the code to
unpack parameters from parameters[] array. unpack parameters from parameters[] array.
:param name: Test function name :param name: Test function name
:param locals: Local variables declaration code :param local_vars: Local variables declaration code
:param args_dispatch: List of dispatch arguments. :param args_dispatch: List of dispatch arguments.
Ex: ['(char *)params[0]', '*((int *)params[1])'] Ex: ['(char *)params[0]', '*((int *)params[1])']
:return: Test function wrapper. :return: Test function wrapper.
@ -300,11 +312,11 @@ void {name}_wrapper( void ** params )
'''.format(name=name, '''.format(name=name,
unused_params='' if args_dispatch else ' (void)params;\n', unused_params='' if args_dispatch else ' (void)params;\n',
args=', '.join(args_dispatch), args=', '.join(args_dispatch),
locals=locals) locals=local_vars)
return wrapper return wrapper
def gen_dispatch(name, deps): def gen_dispatch(name, dependencies):
""" """
Test suite code template main_test.function defines a C function Test suite code template main_test.function defines a C function
array to contain test case functions. This function generates an array to contain test case functions. This function generates an
@ -314,18 +326,18 @@ def gen_dispatch(name, deps):
dependencies are met, else NULL is assigned. dependencies are met, else NULL is assigned.
:param name: Test function name :param name: Test function name
:param deps: List of dependencies :param dependencies: List of dependencies
:return: Dispatch code. :return: Dispatch code.
""" """
if len(deps): if dependencies:
ifdef = gen_deps_one_line(deps) preprocessor_check = gen_dependencies_one_line(dependencies)
dispatch_code = ''' dispatch_code = '''
{ifdef} {preprocessor_check}
{name}_wrapper, {name}_wrapper,
#else #else
NULL, NULL,
#endif #endif
'''.format(ifdef=ifdef, name=name) '''.format(preprocessor_check=preprocessor_check, name=name)
else: else:
dispatch_code = ''' dispatch_code = '''
{name}_wrapper, {name}_wrapper,
@ -350,12 +362,12 @@ def parse_until_pattern(funcs_f, end_regex):
headers += line headers += line
else: else:
raise GeneratorInputError("file: %s - end pattern [%s] not found!" % raise GeneratorInputError("file: %s - end pattern [%s] not found!" %
(funcs_f.name, end_regex)) (funcs_f.name, end_regex))
return headers return headers
def parse_suite_deps(funcs_f): def parse_suite_dependencies(funcs_f):
""" """
Parses test suite dependencies specified at the top of a Parses test suite dependencies specified at the top of a
.function file, that starts with pattern BEGIN_DEPENDENCIES .function file, that starts with pattern BEGIN_DEPENDENCIES
@ -365,21 +377,22 @@ def parse_suite_deps(funcs_f):
:param funcs_f: file object for .functions file :param funcs_f: file object for .functions file
:return: List of test suite dependencies. :return: List of test suite dependencies.
""" """
deps = [] dependencies = []
for line in funcs_f: for line in funcs_f:
m = re.search('depends_on\:(.*)', line.strip()) match = re.search('depends_on:(.*)', line.strip())
if m: if match:
deps += [x.strip() for x in m.group(1).split(':')] dependencies += [x.strip() for x in match.group(1).split(':')]
if re.search(END_DEP_REGEX, line): if re.search(END_DEP_REGEX, line):
break break
else: else:
raise GeneratorInputError("file: %s - end dependency pattern [%s]" raise GeneratorInputError("file: %s - end dependency pattern [%s]"
" not found!" % (funcs_f.name, END_DEP_REGEX)) " not found!" % (funcs_f.name,
END_DEP_REGEX))
return deps return dependencies
def parse_function_deps(line): def parse_function_dependencies(line):
""" """
Parses function dependencies, that are in the same line as Parses function dependencies, that are in the same line as
comment BEGIN_CASE. Dependencies are specified after pattern comment BEGIN_CASE. Dependencies are specified after pattern
@ -388,14 +401,15 @@ def parse_function_deps(line):
:param line: Line from .functions file that has dependencies. :param line: Line from .functions file that has dependencies.
:return: List of dependencies. :return: List of dependencies.
""" """
deps = [] dependencies = []
m = re.search(BEGIN_CASE_REGEX, line) match = re.search(BEGIN_CASE_REGEX, line)
dep_str = m.group(1) dep_str = match.group(1)
if len(dep_str): if dep_str:
m = re.search('depends_on:(.*)', dep_str) match = re.search('depends_on:(.*)', dep_str)
if m: if match:
deps = [x.strip() for x in m.group(1).strip().split(':')] dependencies = [x.strip()
return deps for x in match.group(1).strip().split(':')]
return dependencies
def parse_function_signature(line): def parse_function_signature(line):
@ -410,31 +424,31 @@ def parse_function_signature(line):
wrapper function and argument dispatch code. wrapper function and argument dispatch code.
""" """
args = [] args = []
locals = '' local_vars = ''
args_dispatch = [] args_dispatch = []
# Check if the test function returns void. # Check if the test function returns void.
m = re.search('\s*void\s+(\w+)\s*\(', line, re.I) match = re.search(r'\s*void\s+(\w+)\s*\(', line, re.I)
if not m: if not match:
raise ValueError("Test function should return 'void'\n%s" % line) raise ValueError("Test function should return 'void'\n%s" % line)
name = m.group(1) name = match.group(1)
line = line[len(m.group(0)):] line = line[len(match.group(0)):]
arg_idx = 0 arg_idx = 0
for arg in line[:line.find(')')].split(','): for arg in line[:line.find(')')].split(','):
arg = arg.strip() arg = arg.strip()
if arg == '': if arg == '':
continue continue
if re.search('int\s+.*', arg.strip()): if re.search(r'int\s+.*', arg.strip()):
args.append('int') args.append('int')
args_dispatch.append('*( (int *) params[%d] )' % arg_idx) args_dispatch.append('*( (int *) params[%d] )' % arg_idx)
elif re.search('char\s*\*\s*.*', arg.strip()): elif re.search(r'char\s*\*\s*.*', arg.strip()):
args.append('char*') args.append('char*')
args_dispatch.append('(char *) params[%d]' % arg_idx) args_dispatch.append('(char *) params[%d]' % arg_idx)
elif re.search('data_t\s*\*\s*.*', arg.strip()): elif re.search(r'data_t\s*\*\s*.*', arg.strip()):
args.append('hex') args.append('hex')
# create a structure # create a structure
pointer_initializer = '(uint8_t *) params[%d]' % arg_idx pointer_initializer = '(uint8_t *) params[%d]' % arg_idx
len_initializer = '*( (uint32_t *) params[%d] )' % (arg_idx+1) len_initializer = '*( (uint32_t *) params[%d] )' % (arg_idx+1)
locals += """ data_t data%d = {%s, %s}; local_vars += """ data_t data%d = {%s, %s};
""" % (arg_idx, pointer_initializer, len_initializer) """ % (arg_idx, pointer_initializer, len_initializer)
args_dispatch.append('&data%d' % arg_idx) args_dispatch.append('&data%d' % arg_idx)
@ -444,37 +458,38 @@ def parse_function_signature(line):
"'char *' or 'data_t'\n%s" % line) "'char *' or 'data_t'\n%s" % line)
arg_idx += 1 arg_idx += 1
return name, args, locals, args_dispatch return name, args, local_vars, args_dispatch
def parse_function_code(funcs_f, deps, suite_deps): def parse_function_code(funcs_f, dependencies, suite_dependencies):
""" """
Parses out a function from function file object and generates Parses out a function from function file object and generates
function and dispatch code. function and dispatch code.
:param funcs_f: file object of the functions file. :param funcs_f: file object of the functions file.
:param deps: List of dependencies :param dependencies: List of dependencies
:param suite_deps: List of test suite dependencies :param suite_dependencies: List of test suite dependencies
:return: Function name, arguments, function code and dispatch code. :return: Function name, arguments, function code and dispatch code.
""" """
code = '#line %d "%s"\n' % (funcs_f.line_no + 1, funcs_f.name) code = '#line %d "%s"\n' % (funcs_f.line_no + 1, funcs_f.name)
for line in funcs_f: for line in funcs_f:
# Check function signature # Check function signature
m = re.match('.*?\s+(\w+)\s*\(', line, re.I) match = re.match(r'.*?\s+(\w+)\s*\(', line, re.I)
if m: if match:
# check if we have full signature i.e. split in more lines # check if we have full signature i.e. split in more lines
if not re.match('.*\)', line): if not re.match(r'.*\)', line):
for lin in funcs_f: for lin in funcs_f:
line += lin line += lin
if re.search('.*?\)', line): if re.search(r'.*?\)', line):
break break
name, args, locals, args_dispatch = parse_function_signature(line) name, args, local_vars, args_dispatch = parse_function_signature(
line)
code += line.replace(name, 'test_' + name) code += line.replace(name, 'test_' + name)
name = 'test_' + name name = 'test_' + name
break break
else: else:
raise GeneratorInputError("file: %s - Test functions not found!" % raise GeneratorInputError("file: %s - Test functions not found!" %
funcs_f.name) funcs_f.name)
for line in funcs_f: for line in funcs_f:
if re.search(END_CASE_REGEX, line): if re.search(END_CASE_REGEX, line):
@ -482,20 +497,22 @@ def parse_function_code(funcs_f, deps, suite_deps):
code += line code += line
else: else:
raise GeneratorInputError("file: %s - end case pattern [%s] not " raise GeneratorInputError("file: %s - end case pattern [%s] not "
"found!" % (funcs_f.name, END_CASE_REGEX)) "found!" % (funcs_f.name, END_CASE_REGEX))
# Add exit label if not present # Add exit label if not present
if code.find('exit:') == -1: if code.find('exit:') == -1:
s = code.rsplit('}', 1) split_code = code.rsplit('}', 1)
if len(s) == 2: if len(split_code) == 2:
code = """exit: code = """exit:
;; ;;
}""".join(s) }""".join(split_code)
code += gen_function_wrapper(name, locals, args_dispatch) code += gen_function_wrapper(name, local_vars, args_dispatch)
ifdef, endif = gen_deps(deps) preprocessor_check_start, preprocessor_check_end = \
dispatch_code = gen_dispatch(name, suite_deps + deps) gen_dependencies(dependencies)
return name, args, ifdef + code + endif, dispatch_code dispatch_code = gen_dispatch(name, suite_dependencies + dependencies)
return (name, args, preprocessor_check_start + code +
preprocessor_check_end, dispatch_code)
def parse_functions(funcs_f): def parse_functions(funcs_f):
@ -508,9 +525,8 @@ def parse_functions(funcs_f):
code, function code and a dict with function identifiers code, function code and a dict with function identifiers
and arguments info. and arguments info.
""" """
suite_headers = ''
suite_helpers = '' suite_helpers = ''
suite_deps = [] suite_dependencies = []
suite_functions = '' suite_functions = ''
func_info = {} func_info = {}
function_idx = 0 function_idx = 0
@ -518,62 +534,61 @@ def parse_functions(funcs_f):
for line in funcs_f: for line in funcs_f:
if re.search(BEGIN_HEADER_REGEX, line): if re.search(BEGIN_HEADER_REGEX, line):
headers = parse_until_pattern(funcs_f, END_HEADER_REGEX) headers = parse_until_pattern(funcs_f, END_HEADER_REGEX)
suite_headers += headers suite_helpers += headers
elif re.search(BEGIN_SUITE_HELPERS_REGEX, line): elif re.search(BEGIN_SUITE_HELPERS_REGEX, line):
helpers = parse_until_pattern(funcs_f, END_SUITE_HELPERS_REGEX) helpers = parse_until_pattern(funcs_f, END_SUITE_HELPERS_REGEX)
suite_helpers += helpers suite_helpers += helpers
elif re.search(BEGIN_DEP_REGEX, line): elif re.search(BEGIN_DEP_REGEX, line):
deps = parse_suite_deps(funcs_f) suite_dependencies += parse_suite_dependencies(funcs_f)
suite_deps += deps
elif re.search(BEGIN_CASE_REGEX, line): elif re.search(BEGIN_CASE_REGEX, line):
deps = parse_function_deps(line) dependencies = parse_function_dependencies(line)
func_name, args, func_code, func_dispatch =\ func_name, args, func_code, func_dispatch =\
parse_function_code(funcs_f, deps, suite_deps) parse_function_code(funcs_f, dependencies, suite_dependencies)
suite_functions += func_code suite_functions += func_code
# Generate dispatch code and enumeration info # Generate dispatch code and enumeration info
if func_name in func_info: if func_name in func_info:
raise GeneratorInputError( raise GeneratorInputError(
"file: %s - function %s re-declared at line %d" % \ "file: %s - function %s re-declared at line %d" %
(funcs_f.name, func_name, funcs_f.line_no)) (funcs_f.name, func_name, funcs_f.line_no))
func_info[func_name] = (function_idx, args) func_info[func_name] = (function_idx, args)
dispatch_code += '/* Function Id: %d */\n' % function_idx dispatch_code += '/* Function Id: %d */\n' % function_idx
dispatch_code += func_dispatch dispatch_code += func_dispatch
function_idx += 1 function_idx += 1
ifdef, endif = gen_deps(suite_deps) func_code = (suite_helpers +
func_code = ifdef + suite_headers + suite_helpers + suite_functions + endif suite_functions).join(gen_dependencies(suite_dependencies))
return suite_deps, dispatch_code, func_code, func_info return suite_dependencies, dispatch_code, func_code, func_info
def escaped_split(str, ch): def escaped_split(inp_str, split_char):
""" """
Split str on character ch but ignore escaped \{ch} Split inp_str on character split_char but ignore if escaped.
Since, return value is used to write back to the intermediate Since, return value is used to write back to the intermediate
data file, any escape characters in the input are retained in the data file, any escape characters in the input are retained in the
output. output.
:param str: String to split :param inp_str: String to split
:param ch: split character :param split_char: split character
:return: List of splits :return: List of splits
""" """
if len(ch) > 1: if len(split_char) > 1:
raise ValueError('Expected split character. Found string!') raise ValueError('Expected split character. Found string!')
out = [] out = []
part = '' part = ''
escape = False escape = False
for i in range(len(str)): for character in inp_str:
if not escape and str[i] == ch: if not escape and character == split_char:
out.append(part) out.append(part)
part = '' part = ''
else: else:
part += str[i] part += character
escape = not escape and str[i] == '\\' escape = not escape and character == '\\'
if len(part): if part:
out.append(part) out.append(part)
return out return out
def parse_test_data(data_f, debug=False): def parse_test_data(data_f):
""" """
Parses .data file for each test case name, test function name, Parses .data file for each test case name, test function name,
test dependencies and test arguments. This information is test dependencies and test arguments. This information is
@ -587,44 +602,44 @@ def parse_test_data(data_f, debug=False):
:return: Generator that yields test name, function name, :return: Generator that yields test name, function name,
dependency list and function argument list. dependency list and function argument list.
""" """
STATE_READ_NAME = 0 __state_read_name = 0
STATE_READ_ARGS = 1 __state_read_args = 1
state = STATE_READ_NAME state = __state_read_name
deps = [] dependencies = []
name = '' name = ''
for line in data_f: for line in data_f:
line = line.strip() line = line.strip()
if len(line) and line[0] == '#': # Skip comments if line and line[0] == '#': # Skip comments
continue continue
# Blank line indicates end of test # Blank line indicates end of test
if len(line) == 0: if not line:
if state == STATE_READ_ARGS: if state == __state_read_args:
raise GeneratorInputError("[%s:%d] Newline before arguments. " raise GeneratorInputError("[%s:%d] Newline before arguments. "
"Test function and arguments " "Test function and arguments "
"missing for %s" % "missing for %s" %
(data_f.name, data_f.line_no, name)) (data_f.name, data_f.line_no, name))
continue continue
if state == STATE_READ_NAME: if state == __state_read_name:
# Read test name # Read test name
name = line name = line
state = STATE_READ_ARGS state = __state_read_args
elif state == STATE_READ_ARGS: elif state == __state_read_args:
# Check dependencies # Check dependencies
m = re.search('depends_on\:(.*)', line) match = re.search('depends_on:(.*)', line)
if m: if match:
deps = [x.strip() for x in m.group(1).split(':') if len( dependencies = [x.strip() for x in match.group(1).split(':')
x.strip())] if len(x.strip())]
else: else:
# Read test vectors # Read test vectors
parts = escaped_split(line, ':') parts = escaped_split(line, ':')
function = parts[0] test_function = parts[0]
args = parts[1:] args = parts[1:]
yield name, function, deps, args yield name, test_function, dependencies, args
deps = [] dependencies = []
state = STATE_READ_NAME state = __state_read_name
if state == STATE_READ_ARGS: if state == __state_read_args:
raise GeneratorInputError("[%s:%d] Newline before arguments. " raise GeneratorInputError("[%s:%d] Newline before arguments. "
"Test function and arguments missing for " "Test function and arguments missing for "
"%s" % (data_f.name, data_f.line_no, name)) "%s" % (data_f.name, data_f.line_no, name))
@ -642,19 +657,19 @@ def gen_dep_check(dep_id, dep):
if dep_id < 0: if dep_id < 0:
raise GeneratorInputError("Dependency Id should be a positive " raise GeneratorInputError("Dependency Id should be a positive "
"integer.") "integer.")
noT, dep = ('!', dep[1:]) if dep[0] == '!' else ('', dep) _not, dep = ('!', dep[1:]) if dep[0] == '!' else ('', dep)
if len(dep) == 0: if not dep:
raise GeneratorInputError("Dependency should not be an empty string.") raise GeneratorInputError("Dependency should not be an empty string.")
dep_check = ''' dep_check = '''
case {id}: case {id}:
{{ {{
#if {noT}defined({macro}) #if {_not}defined({macro})
ret = DEPENDENCY_SUPPORTED; ret = DEPENDENCY_SUPPORTED;
#else #else
ret = DEPENDENCY_NOT_SUPPORTED; ret = DEPENDENCY_NOT_SUPPORTED;
#endif #endif
}} }}
break;'''.format(noT=noT, macro=dep, id=dep_id) break;'''.format(_not=_not, macro=dep, id=dep_id)
return dep_check return dep_check
@ -670,7 +685,7 @@ def gen_expression_check(exp_id, exp):
if exp_id < 0: if exp_id < 0:
raise GeneratorInputError("Expression Id should be a positive " raise GeneratorInputError("Expression Id should be a positive "
"integer.") "integer.")
if len(exp) == 0: if not exp:
raise GeneratorInputError("Expression should not be an empty string.") raise GeneratorInputError("Expression should not be an empty string.")
exp_code = ''' exp_code = '''
case {exp_id}: case {exp_id}:
@ -681,28 +696,28 @@ def gen_expression_check(exp_id, exp):
return exp_code return exp_code
def write_deps(out_data_f, test_deps, unique_deps): def write_dependencies(out_data_f, test_dependencies, unique_dependencies):
""" """
Write dependencies to intermediate test data file, replacing Write dependencies to intermediate test data file, replacing
the string form with identifiers. Also, generates dependency the string form with identifiers. Also, generates dependency
check code. check code.
:param out_data_f: Output intermediate data file :param out_data_f: Output intermediate data file
:param test_deps: Dependencies :param test_dependencies: Dependencies
:param unique_deps: Mutable list to track unique dependencies :param unique_dependencies: Mutable list to track unique dependencies
that are global to this re-entrant function. that are global to this re-entrant function.
:return: returns dependency check code. :return: returns dependency check code.
""" """
dep_check_code = '' dep_check_code = ''
if len(test_deps): if test_dependencies:
out_data_f.write('depends_on') out_data_f.write('depends_on')
for dep in test_deps: for dep in test_dependencies:
if dep not in unique_deps: if dep not in unique_dependencies:
unique_deps.append(dep) unique_dependencies.append(dep)
dep_id = unique_deps.index(dep) dep_id = unique_dependencies.index(dep)
dep_check_code += gen_dep_check(dep_id, dep) dep_check_code += gen_dep_check(dep_id, dep)
else: else:
dep_id = unique_deps.index(dep) dep_id = unique_dependencies.index(dep)
out_data_f.write(':' + str(dep_id)) out_data_f.write(':' + str(dep_id))
out_data_f.write('\n') out_data_f.write('\n')
return dep_check_code return dep_check_code
@ -722,12 +737,12 @@ def write_parameters(out_data_f, test_args, func_args, unique_expressions):
:return: Returns expression check code. :return: Returns expression check code.
""" """
expression_code = '' expression_code = ''
for i in range(len(test_args)): for i, _ in enumerate(test_args):
typ = func_args[i] typ = func_args[i]
val = test_args[i] val = test_args[i]
# check if val is a non literal int val (i.e. an expression) # check if val is a non literal int val (i.e. an expression)
if typ == 'int' and not re.match('(\d+$)|((0x)?[0-9a-fA-F]+$)', val): if typ == 'int' and not re.match(r'(\d+$)|((0x)?[0-9a-fA-F]+$)', val):
typ = 'exp' typ = 'exp'
if val not in unique_expressions: if val not in unique_expressions:
unique_expressions.append(val) unique_expressions.append(val)
@ -744,33 +759,33 @@ def write_parameters(out_data_f, test_args, func_args, unique_expressions):
return expression_code return expression_code
def gen_suite_deps_checks(suite_deps, dep_check_code, expression_code): def gen_suite_dep_checks(suite_dependencies, dep_check_code, expression_code):
""" """
Generates preprocessor checks for test suite dependencies. Generates preprocessor checks for test suite dependencies.
:param suite_deps: Test suite dependencies read from the :param suite_dependencies: Test suite dependencies read from the
.functions file. .functions file.
:param dep_check_code: Dependency check code :param dep_check_code: Dependency check code
:param expression_code: Expression check code :param expression_code: Expression check code
:return: Dependency and expression code guarded by test suite :return: Dependency and expression code guarded by test suite
dependencies. dependencies.
""" """
if len(suite_deps): if suite_dependencies:
ifdef = gen_deps_one_line(suite_deps) preprocessor_check = gen_dependencies_one_line(suite_dependencies)
dep_check_code = ''' dep_check_code = '''
{ifdef} {preprocessor_check}
{code} {code}
#endif #endif
'''.format(ifdef=ifdef, code=dep_check_code) '''.format(preprocessor_check=preprocessor_check, code=dep_check_code)
expression_code = ''' expression_code = '''
{ifdef} {preprocessor_check}
{code} {code}
#endif #endif
'''.format(ifdef=ifdef, code=expression_code) '''.format(preprocessor_check=preprocessor_check, code=expression_code)
return dep_check_code, expression_code return dep_check_code, expression_code
def gen_from_test_data(data_f, out_data_f, func_info, suite_deps): def gen_from_test_data(data_f, out_data_f, func_info, suite_dependencies):
""" """
This function reads test case name, dependencies and test vectors This function reads test case name, dependencies and test vectors
from the .data file. This information is correlated with the test from the .data file. This information is correlated with the test
@ -785,19 +800,20 @@ def gen_from_test_data(data_f, out_data_f, func_info, suite_deps):
:param out_data_f:Output intermediate data file :param out_data_f:Output intermediate data file
:param func_info: Dict keyed by function and with function id :param func_info: Dict keyed by function and with function id
and arguments info and arguments info
:param suite_deps: Test suite deps :param suite_dependencies: Test suite dependencies
:return: Returns dependency and expression check code :return: Returns dependency and expression check code
""" """
unique_deps = [] unique_dependencies = []
unique_expressions = [] unique_expressions = []
dep_check_code = '' dep_check_code = ''
expression_code = '' expression_code = ''
for test_name, function_name, test_deps, test_args in parse_test_data( for test_name, function_name, test_dependencies, test_args in \
data_f): parse_test_data(data_f):
out_data_f.write(test_name + '\n') out_data_f.write(test_name + '\n')
# Write deps # Write dependencies
dep_check_code += write_deps(out_data_f, test_deps, unique_deps) dep_check_code += write_dependencies(out_data_f, test_dependencies,
unique_dependencies)
# Write test function name # Write test function name
test_function_name = 'test_' + function_name test_function_name = 'test_' + function_name
@ -810,35 +826,143 @@ def gen_from_test_data(data_f, out_data_f, func_info, suite_deps):
# Write parameters # Write parameters
if len(test_args) != len(func_args): if len(test_args) != len(func_args):
raise GeneratorInputError("Invalid number of arguments in test " raise GeneratorInputError("Invalid number of arguments in test "
"%s. See function %s signature." % ( "%s. See function %s signature." %
test_name, function_name)) (test_name, function_name))
expression_code += write_parameters(out_data_f, test_args, func_args, expression_code += write_parameters(out_data_f, test_args, func_args,
unique_expressions) unique_expressions)
# Write a newline as test case separator # Write a newline as test case separator
out_data_f.write('\n') out_data_f.write('\n')
dep_check_code, expression_code = gen_suite_deps_checks( dep_check_code, expression_code = gen_suite_dep_checks(
suite_deps, dep_check_code, expression_code) suite_dependencies, dep_check_code, expression_code)
return dep_check_code, expression_code return dep_check_code, expression_code
def generate_code(funcs_file, data_file, template_file, platform_file, def add_input_info(funcs_file, data_file, template_file,
helpers_file, suites_dir, c_file, out_data_file): c_file, snippets):
""" """
Generates C source code from test suite file, data file, common Add generator input info in snippets.
helpers file and platform file.
:param funcs_file: Functions file object :param funcs_file: Functions file object
:param data_file: Data file object :param data_file: Data file object
:param template_file: Template file object :param template_file: Template file object
:param platform_file: Platform file object
:param helpers_file: Helper functions file object
:param suites_dir: Test suites dir
:param c_file: Output C file object :param c_file: Output C file object
:param out_data_file: Output intermediate data file object :param snippets: Dictionary to contain code pieces to be
substituted in the template.
:return: :return:
""" """
snippets['test_file'] = c_file
snippets['test_main_file'] = template_file
snippets['test_case_file'] = funcs_file
snippets['test_case_data_file'] = data_file
def read_code_from_input_files(platform_file, helpers_file,
out_data_file, snippets):
"""
Read code from input files and create substitutions for replacement
strings in the template file.
:param platform_file: Platform file object
:param helpers_file: Helper functions file object
:param out_data_file: Output intermediate data file object
:param snippets: Dictionary to contain code pieces to be
substituted in the template.
:return:
"""
# Read helpers
with open(helpers_file, 'r') as help_f, open(platform_file, 'r') as \
platform_f:
snippets['test_common_helper_file'] = helpers_file
snippets['test_common_helpers'] = help_f.read()
snippets['test_platform_file'] = platform_file
snippets['platform_code'] = platform_f.read().replace(
'DATA_FILE', out_data_file.replace('\\', '\\\\')) # escape '\'
def write_test_source_file(template_file, c_file, snippets):
"""
Write output source file with generated source code.
:param template_file: Template file name
:param c_file: Output source file
:param snippets: Generated and code snippets
:return:
"""
with open(template_file, 'r') as template_f, open(c_file, 'w') as c_f:
line_no = 1
for line in template_f.readlines():
# Update line number. +1 as #line directive sets next line number
snippets['line_no'] = line_no + 1
code = line.format(**snippets)
c_f.write(code)
line_no += 1
def parse_function_file(funcs_file, snippets):
"""
Parse function file and generate function dispatch code.
:param funcs_file: Functions file name
:param snippets: Dictionary to contain code pieces to be
substituted in the template.
:return:
"""
with FileWrapper(funcs_file) as funcs_f:
suite_dependencies, dispatch_code, func_code, func_info = \
parse_functions(funcs_f)
snippets['functions_code'] = func_code
snippets['dispatch_code'] = dispatch_code
return suite_dependencies, func_info
def generate_intermediate_data_file(data_file, out_data_file,
suite_dependencies, func_info, snippets):
"""
Generates intermediate data file from input data file and
information read from functions file.
:param data_file: Data file name
:param out_data_file: Output/Intermediate data file
:param suite_dependencies: List of suite dependencies.
:param func_info: Function info parsed from functions file.
:param snippets: Dictionary to contain code pieces to be
substituted in the template.
:return:
"""
with FileWrapper(data_file) as data_f, \
open(out_data_file, 'w') as out_data_f:
dep_check_code, expression_code = gen_from_test_data(
data_f, out_data_f, func_info, suite_dependencies)
snippets['dep_check_code'] = dep_check_code
snippets['expression_code'] = expression_code
def generate_code(**input_info):
"""
Generates C source code from test suite file, data file, common
helpers file and platform file.
input_info expands to following parameters:
funcs_file: Functions file object
data_file: Data file object
template_file: Template file object
platform_file: Platform file object
helpers_file: Helper functions file object
suites_dir: Test suites dir
c_file: Output C file object
out_data_file: Output intermediate data file object
:return:
"""
funcs_file = input_info['funcs_file']
data_file = input_info['data_file']
template_file = input_info['template_file']
platform_file = input_info['platform_file']
helpers_file = input_info['helpers_file']
suites_dir = input_info['suites_dir']
c_file = input_info['c_file']
out_data_file = input_info['out_data_file']
for name, path in [('Functions file', funcs_file), for name, path in [('Functions file', funcs_file),
('Data file', data_file), ('Data file', data_file),
('Template file', template_file), ('Template file', template_file),
@ -848,44 +972,15 @@ def generate_code(funcs_file, data_file, template_file, platform_file,
if not os.path.exists(path): if not os.path.exists(path):
raise IOError("ERROR: %s [%s] not found!" % (name, path)) raise IOError("ERROR: %s [%s] not found!" % (name, path))
snippets = {'generator_script' : os.path.basename(__file__)} snippets = {'generator_script': os.path.basename(__file__)}
read_code_from_input_files(platform_file, helpers_file,
# Read helpers out_data_file, snippets)
with open(helpers_file, 'r') as help_f, open(platform_file, 'r') as \ add_input_info(funcs_file, data_file, template_file,
platform_f: c_file, snippets)
snippets['test_common_helper_file'] = helpers_file suite_dependencies, func_info = parse_function_file(funcs_file, snippets)
snippets['test_common_helpers'] = help_f.read() generate_intermediate_data_file(data_file, out_data_file,
snippets['test_platform_file'] = platform_file suite_dependencies, func_info, snippets)
snippets['platform_code'] = platform_f.read().replace( write_test_source_file(template_file, c_file, snippets)
'DATA_FILE', out_data_file.replace('\\', '\\\\')) # escape '\'
# Function code
with FileWrapper(funcs_file) as funcs_f, FileWrapper(data_file) as \
data_f, open(out_data_file, 'w') as out_data_f:
suite_deps, dispatch_code, func_code, func_info = parse_functions(
funcs_f)
snippets['functions_code'] = func_code
snippets['dispatch_code'] = dispatch_code
dep_check_code, expression_code = gen_from_test_data(
data_f, out_data_f, func_info, suite_deps)
snippets['dep_check_code'] = dep_check_code
snippets['expression_code'] = expression_code
snippets['test_file'] = c_file
snippets['test_main_file'] = template_file
snippets['test_case_file'] = funcs_file
snippets['test_case_data_file'] = data_file
# Read Template
# Add functions
#
with open(template_file, 'r') as template_f, open(c_file, 'w') as c_f:
line_no = 1
for line in template_f.readlines():
# Update line number. +1 as #line directive sets next line number
snippets['line_no'] = line_no + 1
code = line.format(**snippets)
c_f.write(code)
line_no += 1
def check_cmd(): def check_cmd():
@ -949,18 +1044,20 @@ def check_cmd():
out_c_file_dir = os.path.dirname(out_c_file) out_c_file_dir = os.path.dirname(out_c_file)
out_data_file_dir = os.path.dirname(out_data_file) out_data_file_dir = os.path.dirname(out_data_file)
for d in [out_c_file_dir, out_data_file_dir]: for directory in [out_c_file_dir, out_data_file_dir]:
if not os.path.exists(d): if not os.path.exists(directory):
os.makedirs(d) os.makedirs(directory)
generate_code(args.funcs_file, args.data_file, args.template_file, generate_code(funcs_file=args.funcs_file, data_file=args.data_file,
args.platform_file, args.helpers_file, args.suites_dir, template_file=args.template_file,
out_c_file, out_data_file) platform_file=args.platform_file,
helpers_file=args.helpers_file, suites_dir=args.suites_dir,
c_file=out_c_file, out_data_file=out_data_file)
if __name__ == "__main__": if __name__ == "__main__":
try: try:
check_cmd() check_cmd()
except GeneratorInputError as e: except GeneratorInputError as err:
script_name = os.path.basename(sys.argv[0]) print("%s: input error: %s" %
print("%s: input error: %s" % (script_name, str(e))) (os.path.basename(sys.argv[0]), str(err)))

View file

@ -15,18 +15,18 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# This file is part of mbed TLS (https://tls.mbed.org) # This file is part of Mbed TLS (https://tls.mbed.org)
""" """
Mbed TLS on-target test suite tests are implemented as mbed-os greentea Mbed TLS on-target test suite tests are implemented as mbed-os Greentea
tests. Greentea tests are implemented in two parts: target test and tests. Greentea tests are implemented in two parts: target test and
host test. Target test is a C application that is built for the host test. Target test is a C application that is built for the
target platform and executes on the target. Host test is a Python target platform and executes on the target. Host test is a Python
class derived from mbed_host_tests.BaseHostTest. Target communicates class derived from mbed_host_tests.BaseHostTest. Target communicates
with the host over serial for the test data. with the host over serial for the test data.
Python tool mbedgt (greentea) is responsible for flashing the test Python tool mbedgt (Greentea) is responsible for flashing the test
binary on to the target and dynamically loading the host test. binary on to the target and dynamically loading the host test.
This script contains the host test for handling target test's This script contains the host test for handling target test's
@ -64,67 +64,69 @@ class TestDataParser(object):
:param data_file: Data file path :param data_file: Data file path
""" """
with open(data_file, 'r') as f: with open(data_file, 'r') as data_f:
self.__parse(f) self.__parse(data_f)
@staticmethod @staticmethod
def __escaped_split(str, ch): def __escaped_split(inp_str, split_char):
""" """
Splits str on ch except when escaped. Splits inp_str on split_char except when escaped.
:param str: String to split :param inp_str: String to split
:param ch: Split character :param split_char: Split character
:return: List of splits :return: List of splits
""" """
if len(ch) > 1: if len(split_char) > 1:
raise ValueError('Expected split character. Found string!') raise ValueError('Expected split character. Found string!')
out = [] out = []
part = '' part = ''
escape = False escape = False
for i in range(len(str)): for character in inp_str:
if not escape and str[i] == ch: if not escape and character == split_char:
out.append(part) out.append(part)
part = '' part = ''
else: else:
part += str[i] part += character
escape = not escape and str[i] == '\\' escape = not escape and character == '\\'
if len(part): if part:
out.append(part) out.append(part)
return out return out
def __parse(self, file): def __parse(self, data_f):
""" """
Parses data file using supplied file object. Parses data file using supplied file object.
:param file: Data file object :param data_f: Data file object
:return: :return:
""" """
for line in file: for line in data_f:
line = line.strip() line = line.strip()
if len(line) == 0: if not line:
continue continue
# Read test name # Read test name
name = line name = line
# Check dependencies # Check dependencies
deps = [] dependencies = []
line = file.next().strip() line = data_f.next().strip()
m = re.search('depends_on\:(.*)', line) match = re.search('depends_on:(.*)', line)
if m: if match:
deps = [int(x) for x in m.group(1).split(':')] dependencies = [int(x) for x in match.group(1).split(':')]
line = file.next().strip() line = data_f.next().strip()
# Read test vectors # Read test vectors
line = line.replace('\\n', '\n') line = line.replace('\\n', '\n')
parts = self.__escaped_split(line, ':') parts = self.__escaped_split(line, ':')
function = int(parts[0]) function_name = int(parts[0])
x = parts[1:] args = parts[1:]
l = len(x) args_count = len(args)
if l % 2 != 0: if args_count % 2 != 0:
raise TestDataParserError("Number of test arguments should " raise TestDataParserError("Number of test arguments should "
"be even: %s" % line) "be even: %s" % line)
args = [(x[i * 2], x[(i * 2) + 1]) for i in range(len(x)/2)] grouped_args = [(args[i * 2], args[(i * 2) + 1])
self.tests.append((name, function, deps, args)) for i in range(len(args)/2)]
self.tests.append((name, function_name, dependencies,
grouped_args))
def get_test_data(self): def get_test_data(self):
""" """
@ -135,8 +137,8 @@ class TestDataParser(object):
class MbedTlsTest(BaseHostTest): class MbedTlsTest(BaseHostTest):
""" """
Host test for mbedtls unit tests. This script is loaded at Host test for Mbed TLS unit tests. This script is loaded at
run time by Greentea for executing mbedtls test suites. Each run time by Greentea for executing Mbed TLS test suites. Each
communication from the target is received in this object as communication from the target is received in this object as
an event, which is then handled by the event handler method an event, which is then handled by the event handler method
decorated by the associated event. Ex: @event_callback('GO'). decorated by the associated event. Ex: @event_callback('GO').
@ -144,7 +146,7 @@ class MbedTlsTest(BaseHostTest):
Target test sends requests for dispatching next test. It reads Target test sends requests for dispatching next test. It reads
tests from the intermediate data file and sends test function tests from the intermediate data file and sends test function
identifier, dependency identifiers, expression identifiers and identifier, dependency identifiers, expression identifiers and
the test data in binary form. Target test checks dependecnies the test data in binary form. Target test checks dependencies
, evaluate integer constant expressions and dispatches the test , evaluate integer constant expressions and dispatches the test
function with received test parameters. function with received test parameters.
@ -169,12 +171,18 @@ class MbedTlsTest(BaseHostTest):
self.test_index = -1 self.test_index = -1
self.dep_index = 0 self.dep_index = 0
self.error_str = dict() self.error_str = dict()
self.error_str[self.DEPENDENCY_SUPPORTED] = 'DEPENDENCY_SUPPORTED' self.error_str[self.DEPENDENCY_SUPPORTED] = \
self.error_str[self.KEY_VALUE_MAPPING_NOT_FOUND] = 'KEY_VALUE_MAPPING_NOT_FOUND' 'DEPENDENCY_SUPPORTED'
self.error_str[self.DEPENDENCY_NOT_SUPPORTED] = 'DEPENDENCY_NOT_SUPPORTED' self.error_str[self.KEY_VALUE_MAPPING_NOT_FOUND] = \
self.error_str[self.DISPATCH_TEST_FN_NOT_FOUND] = 'DISPATCH_TEST_FN_NOT_FOUND' 'KEY_VALUE_MAPPING_NOT_FOUND'
self.error_str[self.DISPATCH_INVALID_TEST_DATA] = 'DISPATCH_INVALID_TEST_DATA' self.error_str[self.DEPENDENCY_NOT_SUPPORTED] = \
self.error_str[self.DISPATCH_UNSUPPORTED_SUITE] = 'DISPATCH_UNSUPPORTED_SUITE' 'DEPENDENCY_NOT_SUPPORTED'
self.error_str[self.DISPATCH_TEST_FN_NOT_FOUND] = \
'DISPATCH_TEST_FN_NOT_FOUND'
self.error_str[self.DISPATCH_INVALID_TEST_DATA] = \
'DISPATCH_INVALID_TEST_DATA'
self.error_str[self.DISPATCH_UNSUPPORTED_SUITE] = \
'DISPATCH_UNSUPPORTED_SUITE'
def setup(self): def setup(self):
""" """
@ -206,13 +214,13 @@ class MbedTlsTest(BaseHostTest):
self.log('{{__testcase_name;%s}}' % name) self.log('{{__testcase_name;%s}}' % name)
@staticmethod @staticmethod
def align_32bit(b): def align_32bit(data_bytes):
""" """
4 byte aligns input byte array. 4 byte aligns input byte array.
:return: :return:
""" """
b += bytearray((4 - (len(b))) % 4) data_bytes += bytearray((4 - (len(data_bytes))) % 4)
@staticmethod @staticmethod
def hex_str_bytes(hex_str): def hex_str_bytes(hex_str):
@ -230,56 +238,56 @@ class MbedTlsTest(BaseHostTest):
raise TestDataParserError("HEX parameter len should be mod of " raise TestDataParserError("HEX parameter len should be mod of "
"2: %s" % hex_str) "2: %s" % hex_str)
b = binascii.unhexlify(hex_str) data_bytes = binascii.unhexlify(hex_str)
return b return data_bytes
@staticmethod @staticmethod
def int32_to_bigendian_bytes(i): def int32_to_big_endian_bytes(i):
""" """
Coverts i to bytearray in big endian format. Coverts i to byte array in big endian format.
:param i: Input integer :param i: Input integer
:return: Output bytes array in big endian or network order :return: Output bytes array in big endian or network order
""" """
b = bytearray([((i >> x) & 0xff) for x in [24, 16, 8, 0]]) data_bytes = bytearray([((i >> x) & 0xff) for x in [24, 16, 8, 0]])
return b return data_bytes
def test_vector_to_bytes(self, function_id, deps, parameters): def test_vector_to_bytes(self, function_id, dependencies, parameters):
""" """
Converts test vector into a byte array that can be sent to the target. Converts test vector into a byte array that can be sent to the target.
:param function_id: Test Function Identifier :param function_id: Test Function Identifier
:param deps: Dependency list :param dependencies: Dependency list
:param parameters: Test function input parameters :param parameters: Test function input parameters
:return: Byte array and its length :return: Byte array and its length
""" """
b = bytearray([len(deps)]) data_bytes = bytearray([len(dependencies)])
if len(deps): if dependencies:
b += bytearray(deps) data_bytes += bytearray(dependencies)
b += bytearray([function_id, len(parameters)]) data_bytes += bytearray([function_id, len(parameters)])
for typ, param in parameters: for typ, param in parameters:
if typ == 'int' or typ == 'exp': if typ == 'int' or typ == 'exp':
i = int(param) i = int(param)
b += 'I' if typ == 'int' else 'E' data_bytes += 'I' if typ == 'int' else 'E'
self.align_32bit(b) self.align_32bit(data_bytes)
b += self.int32_to_bigendian_bytes(i) data_bytes += self.int32_to_big_endian_bytes(i)
elif typ == 'char*': elif typ == 'char*':
param = param.strip('"') param = param.strip('"')
i = len(param) + 1 # + 1 for null termination i = len(param) + 1 # + 1 for null termination
b += 'S' data_bytes += 'S'
self.align_32bit(b) self.align_32bit(data_bytes)
b += self.int32_to_bigendian_bytes(i) data_bytes += self.int32_to_big_endian_bytes(i)
b += bytearray(list(param)) data_bytes += bytearray(list(param))
b += '\0' # Null terminate data_bytes += '\0' # Null terminate
elif typ == 'hex': elif typ == 'hex':
hb = self.hex_str_bytes(param) binary_data = self.hex_str_bytes(param)
b += 'H' data_bytes += 'H'
self.align_32bit(b) self.align_32bit(data_bytes)
i = len(hb) i = len(binary_data)
b += self.int32_to_bigendian_bytes(i) data_bytes += self.int32_to_big_endian_bytes(i)
b += hb data_bytes += binary_data
length = self.int32_to_bigendian_bytes(len(b)) length = self.int32_to_big_endian_bytes(len(data_bytes))
return b, length return data_bytes, length
def run_next_test(self): def run_next_test(self):
""" """
@ -289,25 +297,26 @@ class MbedTlsTest(BaseHostTest):
self.test_index += 1 self.test_index += 1
self.dep_index = 0 self.dep_index = 0
if self.test_index < len(self.tests): if self.test_index < len(self.tests):
name, function_id, deps, args = self.tests[self.test_index] name, function_id, dependencies, args = self.tests[self.test_index]
self.run_test(name, function_id, deps, args) self.run_test(name, function_id, dependencies, args)
else: else:
self.notify_complete(True) self.notify_complete(True)
def run_test(self, name, function_id, deps, args): def run_test(self, name, function_id, dependencies, args):
""" """
Execute the test on target by sending next test information. Execute the test on target by sending next test information.
:param name: Test name :param name: Test name
:param function_id: function identifier :param function_id: function identifier
:param deps: Dependencies list :param dependencies: Dependencies list
:param args: test parameters :param args: test parameters
:return: :return:
""" """
self.log("Running: %s" % name) self.log("Running: %s" % name)
bytes, length = self.test_vector_to_bytes(function_id, deps, args) param_bytes, length = self.test_vector_to_bytes(function_id,
self.send_kv(length, bytes) dependencies, args)
self.send_kv(length, param_bytes)
@staticmethod @staticmethod
def get_result(value): def get_result(value):
@ -319,52 +328,52 @@ class MbedTlsTest(BaseHostTest):
try: try:
return int(value) return int(value)
except ValueError: except ValueError:
ValueError("Result should return error number. Instead received %s" % value) ValueError("Result should return error number. "
"Instead received %s" % value)
return 0 return 0
@event_callback('GO') @event_callback('GO')
def on_go(self, key, value, timestamp): def on_go(self, _key, _value, _timestamp):
""" """
Sent by the target to start first test. Sent by the target to start first test.
:param key: Event key :param _key: Event key
:param value: Value. ignored :param _value: Value. ignored
:param timestamp: Timestamp ignored. :param _timestamp: Timestamp ignored.
:return: :return:
""" """
self.run_next_test() self.run_next_test()
@event_callback("R") @event_callback("R")
def on_result(self, key, value, timestamp): def on_result(self, _key, value, _timestamp):
""" """
Handle result. Prints test start, finish required by Greentea Handle result. Prints test start, finish required by Greentea
to detect test execution. to detect test execution.
:param key: Event key :param _key: Event key
:param value: Value. ignored :param value: Value. ignored
:param timestamp: Timestamp ignored. :param _timestamp: Timestamp ignored.
:return: :return:
""" """
int_val = self.get_result(value) int_val = self.get_result(value)
name, function, deps, args = self.tests[self.test_index] name, _, _, _ = self.tests[self.test_index]
self.log('{{__testcase_start;%s}}' % name) self.log('{{__testcase_start;%s}}' % name)
self.log('{{__testcase_finish;%s;%d;%d}}' % (name, int_val == 0, self.log('{{__testcase_finish;%s;%d;%d}}' % (name, int_val == 0,
int_val != 0)) int_val != 0))
self.run_next_test() self.run_next_test()
@event_callback("F") @event_callback("F")
def on_failure(self, key, value, timestamp): def on_failure(self, _key, value, _timestamp):
""" """
Handles test execution failure. That means dependency not supported or Handles test execution failure. That means dependency not supported or
Test function not supported. Hence marking test as skipped. Test function not supported. Hence marking test as skipped.
:param key: Event key :param _key: Event key
:param value: Value. ignored :param value: Value. ignored
:param timestamp: Timestamp ignored. :param _timestamp: Timestamp ignored.
:return: :return:
""" """
int_val = self.get_result(value) int_val = self.get_result(value)
name, function, deps, args = self.tests[self.test_index]
if int_val in self.error_str: if int_val in self.error_str:
err = self.error_str[int_val] err = self.error_str[int_val]
else: else:

File diff suppressed because it is too large Load diff