From 4b54323bcb3b5ea91cec21067146cb702c7d9ec7 Mon Sep 17 00:00:00 2001 From: Azim Khan Date: Fri, 30 Jun 2017 09:35:21 +0100 Subject: [PATCH] Unit test generate_copy.py --- tests/scripts/generate_code.py | 144 ++--- tests/scripts/generate_code_ut.py | 842 ++++++++++++++++++++++++++++++ 2 files changed, 920 insertions(+), 66 deletions(-) create mode 100644 tests/scripts/generate_code_ut.py diff --git a/tests/scripts/generate_code.py b/tests/scripts/generate_code.py index c6fc03f53b..b0b368650e 100644 --- a/tests/scripts/generate_code.py +++ b/tests/scripts/generate_code.py @@ -1,6 +1,6 @@ """ -mbed SDK -Copyright (c) 2017-2018 ARM Limited +mbed TLS +Copyright (c) 2017 ARM Limited Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,17 +25,15 @@ import shutil Generates code in following structure. / -|-- host_tests/ -| |-- mbedtls_test.py -| |-- mbedtls/ -| | |-- / -| | | |-- main.c -| | | |-- *.data files -| | ... -| | |-- / -| | | |-- main.c -| | | |-- *.data files -| | | + |-- mbedtls/ + | |-- / + | | |-- main.c + | | |-- *.data files + | ... + | |-- / + | | |-- main.c + | | |-- *.data files + | | """ @@ -56,6 +54,44 @@ class InvalidFileFormat(Exception): pass +class FileWrapper(file): + """ + File wrapper class. Provides reading with line no. tracking. + """ + + def __init__(self, file_name): + """ + Init file handle. + + :param file_name: + """ + super(FileWrapper, self).__init__(file_name, 'r') + self.line_no = 0 + + def next(self): + """ + Iterator return impl. + :return: + """ + line = super(FileWrapper, self).next() + if line: + self.line_no += 1 + return line + + def readline(self, limit=0): + """ + Wrap the base class readline. + + :param limit: + :return: + """ + return self.next() + + +def split_dep(dep): + return ('!', dep[1:]) if dep[0] == '!' else ('', dep) + + def gen_deps(deps): """ Generates dependency i.e. if def and endif code @@ -63,16 +99,9 @@ def gen_deps(deps): :param deps: :return: """ - dep_start = '' - dep_end = '' - for dep in deps: - if dep[0] == '!': - noT = '!' - dep = dep[1:] - else: - noT = '' - dep_start += '#if %sdefined(%s)\n' % (noT, dep) - dep_end = '#endif /* %s%s */\n' % (noT, dep) + dep_end + dep_start = ''.join(['#if %sdefined(%s)\n' % split_dep(x) for x in deps]) + dep_end = ''.join(['#endif /* %s */\n' % x for x in reversed(deps)]) + return dep_start, dep_end @@ -83,22 +112,16 @@ def gen_deps_one_line(deps): :param deps: :return: """ - defines = [] - for dep in deps: - if dep[0] == '!': - noT = '!' - dep = dep[1:] - else: - noT = '' - defines.append('%sdefined(%s)' % (noT, dep)) - return '#if ' + ' && '.join(defines) + defines = ('#if ' if len(deps) else '') + ' && '.join(['%sdefined(%s)' % split_dep(x) for x in deps]) + return defines -def gen_function_wrapper(name, args_dispatch): +def gen_function_wrapper(name, locals, args_dispatch): """ Creates test function code :param name: + :param locals: :param args_dispatch: :return: """ @@ -110,9 +133,9 @@ void {name}_wrapper( void ** params ) {locals} {name}( {args} ); }} -'''.format(name=name, unused_params='(void)params;' if len(args_dispatch[1]) == 0 else '', - args=', '.join(args_dispatch[1]), - locals=args_dispatch[0]) +'''.format(name=name, unused_params='(void)params;' if len(args_dispatch) == 0 else '', + args=', '.join(args_dispatch), + locals=locals) return wrapper @@ -141,37 +164,33 @@ def gen_dispatch(name, deps): return dispatch_code -def parse_suite_headers(line_no, funcs_f): +def parse_suite_headers(funcs_f): """ Parses function headers. - :param line_no: :param funcs_f: :return: """ - headers = '#line %d "%s"\n' % (line_no + 1, funcs_f.name) + headers = '#line %d "%s"\n' % (funcs_f.line_no + 1, funcs_f.name) for line in funcs_f: - line_no += 1 if re.search(END_HEADER_REGEX, line): break headers += line else: raise InvalidFileFormat("file: %s - end header pattern [%s] not found!" % (funcs_f.name, END_HEADER_REGEX)) - return line_no, headers + return headers -def parse_suite_deps(line_no, funcs_f): +def parse_suite_deps(funcs_f): """ Parses function dependencies. - :param line_no: :param funcs_f: :return: """ deps = [] for line in funcs_f: - line_no += 1 m = re.search('depends_on\:(.*)', line.strip()) if m: deps += [x.strip() for x in m.group(1).split(':')] @@ -180,7 +199,7 @@ def parse_suite_deps(line_no, funcs_f): else: raise InvalidFileFormat("file: %s - end dependency pattern [%s] not found!" % (funcs_f.name, END_DEP_REGEX)) - return line_no, deps + return deps def parse_function_deps(line): @@ -195,7 +214,7 @@ def parse_function_deps(line): if len(dep_str): m = re.search('depends_on:(.*)', dep_str) if m: - deps = m.group(1).strip().split(':') + deps = [x.strip() for x in m.group(1).strip().split(':')] return deps @@ -234,13 +253,13 @@ def parse_function_signature(line): args_dispatch.append('&hex%d' % arg_idx) arg_idx += 1 else: - raise ValueError("Test function arguments can only be 'int' or 'char *'\n%s" % line) + raise ValueError("Test function arguments can only be 'int', 'char *' or 'HexParam_t'\n%s" % line) arg_idx += 1 - return name, args, (locals, args_dispatch) + return name, args, locals, args_dispatch -def parse_function_code(line_no, funcs_f, deps, suite_deps): +def parse_function_code(funcs_f, deps, suite_deps): """ :param line_no: @@ -249,9 +268,8 @@ def parse_function_code(line_no, funcs_f, deps, suite_deps): :param suite_deps: :return: """ - code = '#line %d "%s"\n' % (line_no + 1, funcs_f.name) + code = '#line %d "%s"\n' % (funcs_f.line_no + 1, funcs_f.name) for line in funcs_f: - line_no += 1 # Check function signature m = re.match('.*?\s+(\w+)\s*\(', line, re.I) if m: @@ -259,10 +277,9 @@ def parse_function_code(line_no, funcs_f, deps, suite_deps): if not re.match('.*\)', line): for lin in funcs_f: line += lin - line_no += 1 if re.search('.*?\)', line): break - name, args, args_dispatch = parse_function_signature(line) + name, args, locals, args_dispatch = parse_function_signature(line) code += line.replace(name, 'test_' + name) name = 'test_' + name break @@ -270,7 +287,6 @@ def parse_function_code(line_no, funcs_f, deps, suite_deps): raise InvalidFileFormat("file: %s - Test functions not found!" % funcs_f.name) for line in funcs_f: - line_no += 1 if re.search(END_CASE_REGEX, line): break code += line @@ -281,16 +297,14 @@ def parse_function_code(line_no, funcs_f, deps, suite_deps): if code.find('exit:') == -1: s = code.rsplit('}', 1) if len(s) == 2: - code = """ -exit: + code = """exit: ;; -} -""".join(s) +}""".join(s) - code += gen_function_wrapper(name, args_dispatch) + code += gen_function_wrapper(name, locals, args_dispatch) ifdef, endif = gen_deps(deps) dispatch_code = gen_dispatch(name, suite_deps + deps) - return line_no, name, args, ifdef + code + endif, dispatch_code + return name, args, ifdef + code + endif, dispatch_code def parse_functions(funcs_f): @@ -300,7 +314,6 @@ def parse_functions(funcs_f): :param funcs_f: :return: """ - line_no = 0 suite_headers = '' suite_deps = [] suite_functions = '' @@ -308,20 +321,19 @@ def parse_functions(funcs_f): function_idx = 0 dispatch_code = '' for line in funcs_f: - line_no += 1 if re.search(BEGIN_HEADER_REGEX, line): - line_no, headers = parse_suite_headers(line_no, funcs_f) + headers = parse_suite_headers(funcs_f) suite_headers += headers elif re.search(BEGIN_DEP_REGEX, line): - line_no, deps = parse_suite_deps(line_no, funcs_f) + deps = parse_suite_deps(funcs_f) suite_deps += deps elif re.search(BEGIN_CASE_REGEX, line): deps = parse_function_deps(line) - line_no, func_name, args, func_code, func_dispatch = parse_function_code(line_no, funcs_f, deps, suite_deps) + func_name, args, func_code, func_dispatch = parse_function_code(funcs_f, deps, suite_deps) suite_functions += func_code # Generate dispatch code and enumeration info assert func_name not in func_info, "file: %s - function %s re-declared at line %d" % \ - (funcs_f.name, func_name, line_no) + (funcs_f.name, func_name, funcs_f.line_no) func_info[func_name] = (function_idx, args) dispatch_code += '/* Function Id: %d */\n' % function_idx dispatch_code += func_dispatch diff --git a/tests/scripts/generate_code_ut.py b/tests/scripts/generate_code_ut.py new file mode 100644 index 0000000000..f941316ef3 --- /dev/null +++ b/tests/scripts/generate_code_ut.py @@ -0,0 +1,842 @@ +""" +mbed TLS +Copyright (c) 2017 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +from StringIO import StringIO +from unittest import TestCase, main as unittest_main +from mock import patch +from generate_code import * + + +""" +Unit tests for generate_code.py +""" + + +class GenDep(TestCase): + """ + Test suite for function gen_dep() + """ + + def test_deps_list(self): + """ + Test that gen_dep() correctly creates deps for given dependency list. + :return: + """ + deps = ['DEP1', 'DEP2'] + dep_start, dep_end = gen_deps(deps) + ifdef1, ifdef2 = dep_start.splitlines() + endif1, endif2 = dep_end.splitlines() + self.assertEqual(ifdef1, '#if defined(DEP1)', 'ifdef generated incorrectly') + self.assertEqual(ifdef2, '#if defined(DEP2)', 'ifdef generated incorrectly') + self.assertEqual(endif1, '#endif /* DEP2 */', 'endif generated incorrectly') + self.assertEqual(endif2, '#endif /* DEP1 */', 'endif generated incorrectly') + + def test_disabled_deps_list(self): + """ + Test that gen_dep() correctly creates deps for given dependency list. + :return: + """ + deps = ['!DEP1', '!DEP2'] + dep_start, dep_end = gen_deps(deps) + ifdef1, ifdef2 = dep_start.splitlines() + endif1, endif2 = dep_end.splitlines() + self.assertEqual(ifdef1, '#if !defined(DEP1)', 'ifdef generated incorrectly') + self.assertEqual(ifdef2, '#if !defined(DEP2)', 'ifdef generated incorrectly') + self.assertEqual(endif1, '#endif /* !DEP2 */', 'endif generated incorrectly') + self.assertEqual(endif2, '#endif /* !DEP1 */', 'endif generated incorrectly') + + def test_mixed_deps_list(self): + """ + Test that gen_dep() correctly creates deps for given dependency list. + :return: + """ + deps = ['!DEP1', 'DEP2'] + dep_start, dep_end = gen_deps(deps) + ifdef1, ifdef2 = dep_start.splitlines() + endif1, endif2 = dep_end.splitlines() + self.assertEqual(ifdef1, '#if !defined(DEP1)', 'ifdef generated incorrectly') + self.assertEqual(ifdef2, '#if defined(DEP2)', 'ifdef generated incorrectly') + self.assertEqual(endif1, '#endif /* DEP2 */', 'endif generated incorrectly') + self.assertEqual(endif2, '#endif /* !DEP1 */', 'endif generated incorrectly') + + def test_empty_deps_list(self): + """ + Test that gen_dep() correctly creates deps for given dependency list. + :return: + """ + deps = [] + dep_start, dep_end = gen_deps(deps) + self.assertEqual(dep_start, '', 'ifdef generated incorrectly') + self.assertEqual(dep_end, '', 'ifdef generated incorrectly') + + def test_large_deps_list(self): + """ + Test that gen_dep() correctly creates deps for given dependency list. + :return: + """ + deps = [] + count = 10 + for i in range(count): + deps.append('DEP%d' % i) + dep_start, dep_end = gen_deps(deps) + self.assertEqual(len(dep_start.splitlines()), count, 'ifdef generated incorrectly') + self.assertEqual(len(dep_end.splitlines()), count, 'ifdef generated incorrectly') + + +class GenDepOneLine(TestCase): + """ + Test Suite for testing gen_deps_one_line() + """ + + def test_deps_list(self): + """ + Test that gen_dep() correctly creates deps for given dependency list. + :return: + """ + deps = ['DEP1', 'DEP2'] + dep_str = gen_deps_one_line(deps) + self.assertEqual(dep_str, '#if defined(DEP1) && defined(DEP2)', 'ifdef generated incorrectly') + + def test_disabled_deps_list(self): + """ + Test that gen_dep() correctly creates deps for given dependency list. + :return: + """ + deps = ['!DEP1', '!DEP2'] + dep_str = gen_deps_one_line(deps) + self.assertEqual(dep_str, '#if !defined(DEP1) && !defined(DEP2)', 'ifdef generated incorrectly') + + def test_mixed_deps_list(self): + """ + Test that gen_dep() correctly creates deps for given dependency list. + :return: + """ + deps = ['!DEP1', 'DEP2'] + dep_str = gen_deps_one_line(deps) + self.assertEqual(dep_str, '#if !defined(DEP1) && defined(DEP2)', 'ifdef generated incorrectly') + + def test_empty_deps_list(self): + """ + Test that gen_dep() correctly creates deps for given dependency list. + :return: + """ + deps = [] + dep_str = gen_deps_one_line(deps) + self.assertEqual(dep_str, '', 'ifdef generated incorrectly') + + def test_large_deps_list(self): + """ + Test that gen_dep() correctly creates deps for given dependency list. + :return: + """ + deps = [] + count = 10 + for i in range(count): + deps.append('DEP%d' % i) + dep_str = gen_deps_one_line(deps) + expected = '#if ' + ' && '.join(['defined(%s)' % x for x in deps]) + self.assertEqual(dep_str, expected, 'ifdef generated incorrectly') + + +class GenFunctionWrapper(TestCase): + """ + Test Suite for testing gen_function_wrapper() + """ + + def test_params_unpack(self): + """ + Test that params are properly unpacked in the function call. + + :return: + """ + code = gen_function_wrapper('test_a', '', ('a', 'b', 'c', 'd')) + expected = ''' +void test_a_wrapper( void ** params ) +{ + + + test_a( a, b, c, d ); +} +''' + self.assertEqual(code, expected) + + def test_local(self): + """ + Test that params are properly unpacked in the function call. + + :return: + """ + code = gen_function_wrapper('test_a', 'int x = 1;', ('x', 'b', 'c', 'd')) + expected = ''' +void test_a_wrapper( void ** params ) +{ + +int x = 1; + test_a( x, b, c, d ); +} +''' + self.assertEqual(code, expected) + + def test_empty_params(self): + """ + Test that params are properly unpacked in the function call. + + :return: + """ + code = gen_function_wrapper('test_a', '', ()) + expected = ''' +void test_a_wrapper( void ** params ) +{ + (void)params; + + test_a( ); +} +''' + self.assertEqual(code, expected) + + +class GenDispatch(TestCase): + """ + Test suite for testing gen_dispatch() + """ + + def test_dispatch(self): + """ + Test that dispatch table entry is generated correctly. + :return: + """ + code = gen_dispatch('test_a', ['DEP1', 'DEP2']) + expected = ''' +#if defined(DEP1) && defined(DEP2) + test_a_wrapper, +#else + NULL, +#endif +''' + self.assertEqual(code, expected) + + def test_empty_deps(self): + """ + Test empty dependency list. + :return: + """ + code = gen_dispatch('test_a', []) + expected = ''' + test_a_wrapper, +''' + self.assertEqual(code, expected) + + +class StringIOWrapper(StringIO, object): + """ + file like class to mock file object in tests. + """ + def __init__(self, file_name, data, line_no = 1): + """ + Init file handle. + + :param file_name: + :param data: + :param line_no: + """ + super(StringIOWrapper, self).__init__(data) + self.line_no = line_no + self.name = file_name + + def next(self): + """ + Iterator return impl. + :return: + """ + line = super(StringIOWrapper, self).next() + return line + + def readline(self, limit=0): + """ + Wrap the base class readline. + + :param limit: + :return: + """ + line = super(StringIOWrapper, self).readline() + if line: + self.line_no += 1 + return line + + +class ParseSuiteHeaders(TestCase): + """ + Test Suite for testing parse_suite_headers(). + """ + + def test_suite_headers(self): + """ + Test that suite headers are parsed correctly. + + :return: + """ + data = '''#include "mbedtls/ecp.h" + +#define ECP_PF_UNKNOWN -1 +/* END_HEADER */ +''' + expected = '''#line 1 "test_suite_ut.function" +#include "mbedtls/ecp.h" + +#define ECP_PF_UNKNOWN -1 +''' + s = StringIOWrapper('test_suite_ut.function', data, line_no=0) + headers = parse_suite_headers(s) + self.assertEqual(headers, expected) + + def test_line_no(self): + """ + Test that #line is set to correct line no. in source .function file. + + :return: + """ + data = '''#include "mbedtls/ecp.h" + +#define ECP_PF_UNKNOWN -1 +/* END_HEADER */ +''' + offset_line_no = 5 + expected = '''#line %d "test_suite_ut.function" +#include "mbedtls/ecp.h" + +#define ECP_PF_UNKNOWN -1 +''' % (offset_line_no + 1) + s = StringIOWrapper('test_suite_ut.function', data, offset_line_no) + headers = parse_suite_headers(s) + self.assertEqual(headers, expected) + + def test_no_end_header_comment(self): + """ + Test that InvalidFileFormat is raised when end header comment is missing. + :return: + """ + data = '''#include "mbedtls/ecp.h" + +#define ECP_PF_UNKNOWN -1 + +''' + s = StringIOWrapper('test_suite_ut.function', data) + self.assertRaises(InvalidFileFormat, parse_suite_headers, s) + + +class ParseSuiteDeps(TestCase): + """ + Test Suite for testing parse_suite_deps(). + """ + + def test_suite_deps(self): + """ + + :return: + """ + data = ''' + * depends_on:MBEDTLS_ECP_C + * END_DEPENDENCIES + */ +''' + expected = ['MBEDTLS_ECP_C'] + s = StringIOWrapper('test_suite_ut.function', data) + deps = parse_suite_deps(s) + self.assertEqual(deps, expected) + + def test_no_end_dep_comment(self): + """ + Test that InvalidFileFormat is raised when end dep comment is missing. + :return: + """ + data = ''' +* depends_on:MBEDTLS_ECP_C +''' + s = StringIOWrapper('test_suite_ut.function', data) + self.assertRaises(InvalidFileFormat, parse_suite_deps, s) + + def test_deps_split(self): + """ + Test that InvalidFileFormat is raised when end dep comment is missing. + :return: + """ + data = ''' + * depends_on:MBEDTLS_ECP_C:A:B: C : D :F : G: !H + * END_DEPENDENCIES + */ +''' + expected = ['MBEDTLS_ECP_C', 'A', 'B', 'C', 'D', 'F', 'G', '!H'] + s = StringIOWrapper('test_suite_ut.function', data) + deps = parse_suite_deps(s) + self.assertEqual(deps, expected) + + +class ParseFuncDeps(TestCase): + """ + Test Suite for testing parse_function_deps() + """ + + def test_function_deps(self): + """ + Test that parse_function_deps() correctly parses function dependencies. + :return: + """ + line = '/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */' + expected = ['MBEDTLS_ENTROPY_NV_SEED', 'MBEDTLS_FS_IO'] + deps = parse_function_deps(line) + self.assertEqual(deps, expected) + + def test_no_deps(self): + """ + Test that parse_function_deps() correctly parses function dependencies. + :return: + """ + line = '/* BEGIN_CASE */' + deps = parse_function_deps(line) + self.assertEqual(deps, []) + + def test_poorly_defined_deps(self): + """ + Test that parse_function_deps() correctly parses function dependencies. + :return: + """ + line = '/* BEGIN_CASE depends_on:MBEDTLS_FS_IO: A : !B:C : F*/' + deps = parse_function_deps(line) + self.assertEqual(deps, ['MBEDTLS_FS_IO', 'A', '!B', 'C', 'F']) + + +class ParseFuncSignature(TestCase): + """ + Test Suite for parse_function_signature(). + """ + + def test_int_and_char_params(self): + """ + + :return: + """ + line = 'void entropy_threshold( char * a, int b, int result )' + name, args, local, arg_dispatch = parse_function_signature(line) + self.assertEqual(name, 'entropy_threshold') + self.assertEqual(args, ['char*', 'int', 'int']) + self.assertEqual(local, '') + self.assertEqual(arg_dispatch, ['(char *) params[0]', '*( (int *) params[1] )', '*( (int *) params[2] )']) + + def test_hex_params(self): + """ + + :return: + """ + line = 'void entropy_threshold( char * a, HexParam_t * h, int result )' + name, args, local, arg_dispatch = parse_function_signature(line) + self.assertEqual(name, 'entropy_threshold') + self.assertEqual(args, ['char*', 'hex', 'int']) + self.assertEqual(local, ' HexParam_t hex1 = {(uint8_t *) params[1], *( (uint32_t *) params[2] )};\n') + self.assertEqual(arg_dispatch, ['(char *) params[0]', '&hex1', '*( (int *) params[3] )']) + + def test_non_void_function(self): + """ + + :return: + """ + line = 'int entropy_threshold( char * a, HexParam_t * h, int result )' + self.assertRaises(ValueError, parse_function_signature, line) + + def test_unsupported_arg(self): + """ + + :return: + """ + line = 'int entropy_threshold( char * a, HexParam_t * h, int * result )' + self.assertRaises(ValueError, parse_function_signature, line) + + def test_no_params(self): + """ + + :return: + """ + line = 'void entropy_threshold()' + name, args, local, arg_dispatch = parse_function_signature(line) + self.assertEqual(name, 'entropy_threshold') + self.assertEqual(args, []) + self.assertEqual(local, '') + self.assertEqual(arg_dispatch, []) + + +class ParseFunctionCode(TestCase): + """ + Test suite for testing parse_function_code() + """ + + def test_no_function(self): + """ + + :return: + """ + data = ''' +No +test +function +''' + s = StringIOWrapper('test_suite_ut.function', data) + self.assertRaises(InvalidFileFormat, parse_function_code, s, [], []) + + def test_no_end_case_comment(self): + """ + + :return: + """ + data = ''' +void test_func() +{ +} +''' + s = StringIOWrapper('test_suite_ut.function', data) + self.assertRaises(InvalidFileFormat, parse_function_code, s, [], []) + + @patch("generate_code.parse_function_signature") + def test_parse_function_signature_called(self, parse_function_signature_mock): + """ + + :return: + """ + parse_function_signature_mock.return_value = ('test_func', [], '', []) + data = ''' +void test_func() +{ +} +''' + s = StringIOWrapper('test_suite_ut.function', data) + self.assertRaises(InvalidFileFormat, parse_function_code, s, [], []) + self.assertTrue(parse_function_signature_mock.called) + parse_function_signature_mock.assert_called_with('void test_func()\n') + + @patch("generate_code.gen_dispatch") + @patch("generate_code.gen_deps") + @patch("generate_code.gen_function_wrapper") + @patch("generate_code.parse_function_signature") + def test_return(self, parse_function_signature_mock, + gen_function_wrapper_mock, + gen_deps_mock, + gen_dispatch_mock): + """ + + :return: + """ + parse_function_signature_mock.return_value = ('func', [], '', []) + gen_function_wrapper_mock.return_value = '' + gen_deps_mock.side_effect = gen_deps + gen_dispatch_mock.side_effect = gen_dispatch + data = ''' +void func() +{ + ba ba black sheep + have you any wool +} +/* END_CASE */ +''' + s = StringIOWrapper('test_suite_ut.function', data) + name, arg, code, dispatch_code = parse_function_code(s, [], []) + + #self.assertRaises(InvalidFileFormat, parse_function_code, s, [], []) + self.assertTrue(parse_function_signature_mock.called) + parse_function_signature_mock.assert_called_with('void func()\n') + gen_function_wrapper_mock.assert_called_with('test_func', '', []) + self.assertEqual(name, 'test_func') + self.assertEqual(arg, []) + expected = '''#line 2 "test_suite_ut.function" +void test_func() +{ + ba ba black sheep + have you any wool +exit: + ;; +} +''' + self.assertEqual(code, expected) + self.assertEqual(dispatch_code, "\n test_func_wrapper,\n") + + @patch("generate_code.gen_dispatch") + @patch("generate_code.gen_deps") + @patch("generate_code.gen_function_wrapper") + @patch("generate_code.parse_function_signature") + def test_with_exit_label(self, parse_function_signature_mock, + gen_function_wrapper_mock, + gen_deps_mock, + gen_dispatch_mock): + """ + + :return: + """ + parse_function_signature_mock.return_value = ('func', [], '', []) + gen_function_wrapper_mock.return_value = '' + gen_deps_mock.side_effect = gen_deps + gen_dispatch_mock.side_effect = gen_dispatch + data = ''' +void func() +{ + ba ba black sheep + have you any wool +exit: + yes sir yes sir + 3 bags full +} +/* END_CASE */ +''' + s = StringIOWrapper('test_suite_ut.function', data) + name, arg, code, dispatch_code = parse_function_code(s, [], []) + + expected = '''#line 2 "test_suite_ut.function" +void test_func() +{ + ba ba black sheep + have you any wool +exit: + yes sir yes sir + 3 bags full +} +''' + self.assertEqual(code, expected) + + +class ParseFunction(TestCase): + """ + Test Suite for testing parse_functions() + """ + + @patch("generate_code.parse_suite_headers") + def test_begin_header(self, parse_suite_headers_mock): + """ + Test that begin header is checked and parse_suite_headers() is called. + :return: + """ + def stop(this): + raise Exception + parse_suite_headers_mock.side_effect = stop + data = '''/* BEGIN_HEADER */ +#include "mbedtls/ecp.h" + +#define ECP_PF_UNKNOWN -1 +/* END_HEADER */ +''' + s = StringIOWrapper('test_suite_ut.function', data) + self.assertRaises(Exception, parse_functions, s) + parse_suite_headers_mock.assert_called_with(s) + self.assertEqual(s.line_no, 2) + + @patch("generate_code.parse_suite_deps") + def test_begin_dep(self, parse_suite_deps_mock): + """ + Test that begin header is checked and parse_suite_headers() is called. + :return: + """ + def stop(this): + raise Exception + parse_suite_deps_mock.side_effect = stop + data = '''/* BEGIN_DEPENDENCIES + * depends_on:MBEDTLS_ECP_C + * END_DEPENDENCIES + */ +''' + s = StringIOWrapper('test_suite_ut.function', data) + self.assertRaises(Exception, parse_functions, s) + parse_suite_deps_mock.assert_called_with(s) + self.assertEqual(s.line_no, 2) + + @patch("generate_code.parse_function_deps") + def test_begin_function_dep(self, parse_function_deps_mock): + """ + Test that begin header is checked and parse_suite_headers() is called. + :return: + """ + def stop(this): + raise Exception + parse_function_deps_mock.side_effect = stop + + deps_str = '/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */\n' + data = '''%svoid test_func() +{ +} +''' % deps_str + s = StringIOWrapper('test_suite_ut.function', data) + self.assertRaises(Exception, parse_functions, s) + parse_function_deps_mock.assert_called_with(deps_str) + self.assertEqual(s.line_no, 2) + + @patch("generate_code.parse_function_code") + @patch("generate_code.parse_function_deps") + def test_return(self, parse_function_deps_mock, parse_function_code_mock): + """ + Test that begin header is checked and parse_suite_headers() is called. + :return: + """ + def stop(this): + raise Exception + parse_function_deps_mock.return_value = [] + in_func_code= '''void test_func() +{ +} +''' + func_dispatch = ''' + test_func_wrapper, +''' + parse_function_code_mock.return_value = 'test_func', [], in_func_code, func_dispatch + deps_str = '/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */\n' + data = '''%svoid test_func() +{ +} +''' % deps_str + s = StringIOWrapper('test_suite_ut.function', data) + suite_deps, dispatch_code, func_code, func_info = parse_functions(s) + parse_function_deps_mock.assert_called_with(deps_str) + parse_function_code_mock.assert_called_with(s, [], []) + self.assertEqual(s.line_no, 5) + self.assertEqual(suite_deps, []) + expected_dispatch_code = '''/* Function Id: 0 */ + + test_func_wrapper, +''' + self.assertEqual(dispatch_code, expected_dispatch_code) + self.assertEqual(func_code, in_func_code) + self.assertEqual(func_info, {'test_func': (0, [])}) + + def test_parsing(self): + """ + Test that begin header is checked and parse_suite_headers() is called. + :return: + """ + data = '''/* BEGIN_HEADER */ +#include "mbedtls/ecp.h" + +#define ECP_PF_UNKNOWN -1 +/* END_HEADER */ + +/* BEGIN_DEPENDENCIES + * depends_on:MBEDTLS_ECP_C + * END_DEPENDENCIES + */ + +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ +void func1() +{ +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ +void func2() +{ +} +/* END_CASE */ +''' + s = StringIOWrapper('test_suite_ut.function', data) + suite_deps, dispatch_code, func_code, func_info = parse_functions(s) + self.assertEqual(s.line_no, 23) + self.assertEqual(suite_deps, ['MBEDTLS_ECP_C']) + + expected_dispatch_code = '''/* Function Id: 0 */ + +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_ENTROPY_NV_SEED) && defined(MBEDTLS_FS_IO) + test_func1_wrapper, +#else + NULL, +#endif +/* Function Id: 1 */ + +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_ENTROPY_NV_SEED) && defined(MBEDTLS_FS_IO) + test_func2_wrapper, +#else + NULL, +#endif +''' + self.assertEqual(dispatch_code, expected_dispatch_code) + expected_func_code = '''#if defined(MBEDTLS_ECP_C) +#line 3 "test_suite_ut.function" +#include "mbedtls/ecp.h" + +#define ECP_PF_UNKNOWN -1 +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#if defined(MBEDTLS_FS_IO) +#line 14 "test_suite_ut.function" +void test_func1() +{ +exit: + ;; +} + +void test_func1_wrapper( void ** params ) +{ + (void)params; + + test_func1( ); +} +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_ENTROPY_NV_SEED */ +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#if defined(MBEDTLS_FS_IO) +#line 20 "test_suite_ut.function" +void test_func2() +{ +exit: + ;; +} + +void test_func2_wrapper( void ** params ) +{ + (void)params; + + test_func2( ); +} +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_ENTROPY_NV_SEED */ +#endif /* MBEDTLS_ECP_C */ +''' + self.assertEqual(func_code, expected_func_code) + self.assertEqual(func_info, {'test_func1': (0, []), 'test_func2': (1, [])}) + + def test_same_function_name(self): + """ + Test that begin header is checked and parse_suite_headers() is called. + :return: + """ + data = '''/* BEGIN_HEADER */ +#include "mbedtls/ecp.h" + +#define ECP_PF_UNKNOWN -1 +/* END_HEADER */ + +/* BEGIN_DEPENDENCIES + * depends_on:MBEDTLS_ECP_C + * END_DEPENDENCIES + */ + +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ +void func() +{ +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ +void func() +{ +} +/* END_CASE */ +''' + s = StringIOWrapper('test_suite_ut.function', data) + self.assertRaises(AssertionError, parse_functions, s) + + +if __name__=='__main__': + unittest_main() \ No newline at end of file