2 # Unit test for generate_test_code.py
4 # Copyright (C) 2018, Arm Limited, All Rights Reserved
5 # SPDX-License-Identifier: Apache-2.0
7 # Licensed under the Apache License, Version 2.0 (the "License"); you may
8 # not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
11 # http://www.apache.org/licenses/LICENSE-2.0
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
19 # This file is part of Mbed TLS (https://tls.mbed.org)
22 Unit tests for generate_test_code.py
25 # pylint: disable=wrong-import-order
28 from StringIO import StringIO
31 from io import StringIO
32 from unittest import TestCase, main as unittest_main
35 from mock import patch
38 from unittest.mock import patch
39 # pylint: enable=wrong-import-order
40 from generate_test_code import gen_dependencies, gen_dependencies_one_line
41 from generate_test_code import gen_function_wrapper, gen_dispatch
42 from generate_test_code import parse_until_pattern, GeneratorInputError
43 from generate_test_code import parse_suite_dependencies
44 from generate_test_code import parse_function_dependencies
45 from generate_test_code import parse_function_arguments, parse_function_code
46 from generate_test_code import parse_functions, END_HEADER_REGEX
47 from generate_test_code import END_SUITE_HELPERS_REGEX, escaped_split
48 from generate_test_code import parse_test_data, gen_dep_check
49 from generate_test_code import gen_expression_check, write_dependencies
50 from generate_test_code import write_parameters, gen_suite_dep_checks
51 from generate_test_code import gen_from_test_data
54 class GenDep(TestCase):
56 Test suite for function gen_dep()
59 def test_dependencies_list(self):
61 Test that gen_dep() correctly creates dependencies for given
65 dependencies = ['DEP1', 'DEP2']
66 dep_start, dep_end = gen_dependencies(dependencies)
67 preprocessor1, preprocessor2 = dep_start.splitlines()
68 endif1, endif2 = dep_end.splitlines()
69 self.assertEqual(preprocessor1, '#if defined(DEP1)',
70 'Preprocessor generated incorrectly')
71 self.assertEqual(preprocessor2, '#if defined(DEP2)',
72 'Preprocessor generated incorrectly')
73 self.assertEqual(endif1, '#endif /* DEP2 */',
74 'Preprocessor generated incorrectly')
75 self.assertEqual(endif2, '#endif /* DEP1 */',
76 'Preprocessor generated incorrectly')
78 def test_disabled_dependencies_list(self):
80 Test that gen_dep() correctly creates dependencies for given
84 dependencies = ['!DEP1', '!DEP2']
85 dep_start, dep_end = gen_dependencies(dependencies)
86 preprocessor1, preprocessor2 = dep_start.splitlines()
87 endif1, endif2 = dep_end.splitlines()
88 self.assertEqual(preprocessor1, '#if !defined(DEP1)',
89 'Preprocessor generated incorrectly')
90 self.assertEqual(preprocessor2, '#if !defined(DEP2)',
91 'Preprocessor generated incorrectly')
92 self.assertEqual(endif1, '#endif /* !DEP2 */',
93 'Preprocessor generated incorrectly')
94 self.assertEqual(endif2, '#endif /* !DEP1 */',
95 'Preprocessor generated incorrectly')
97 def test_mixed_dependencies_list(self):
99 Test that gen_dep() correctly creates dependencies for given
103 dependencies = ['!DEP1', 'DEP2']
104 dep_start, dep_end = gen_dependencies(dependencies)
105 preprocessor1, preprocessor2 = dep_start.splitlines()
106 endif1, endif2 = dep_end.splitlines()
107 self.assertEqual(preprocessor1, '#if !defined(DEP1)',
108 'Preprocessor generated incorrectly')
109 self.assertEqual(preprocessor2, '#if defined(DEP2)',
110 'Preprocessor generated incorrectly')
111 self.assertEqual(endif1, '#endif /* DEP2 */',
112 'Preprocessor generated incorrectly')
113 self.assertEqual(endif2, '#endif /* !DEP1 */',
114 'Preprocessor generated incorrectly')
116 def test_empty_dependencies_list(self):
118 Test that gen_dep() correctly creates dependencies for given
123 dep_start, dep_end = gen_dependencies(dependencies)
124 self.assertEqual(dep_start, '', 'Preprocessor generated incorrectly')
125 self.assertEqual(dep_end, '', 'Preprocessor generated incorrectly')
127 def test_large_dependencies_list(self):
129 Test that gen_dep() correctly creates dependencies for given
135 for i in range(count):
136 dependencies.append('DEP%d' % i)
137 dep_start, dep_end = gen_dependencies(dependencies)
138 self.assertEqual(len(dep_start.splitlines()), count,
139 'Preprocessor generated incorrectly')
140 self.assertEqual(len(dep_end.splitlines()), count,
141 'Preprocessor generated incorrectly')
144 class GenDepOneLine(TestCase):
146 Test Suite for testing gen_dependencies_one_line()
149 def test_dependencies_list(self):
151 Test that gen_dep() correctly creates dependencies for given
155 dependencies = ['DEP1', 'DEP2']
156 dep_str = gen_dependencies_one_line(dependencies)
157 self.assertEqual(dep_str, '#if defined(DEP1) && defined(DEP2)',
158 'Preprocessor generated incorrectly')
160 def test_disabled_dependencies_list(self):
162 Test that gen_dep() correctly creates dependencies for given
166 dependencies = ['!DEP1', '!DEP2']
167 dep_str = gen_dependencies_one_line(dependencies)
168 self.assertEqual(dep_str, '#if !defined(DEP1) && !defined(DEP2)',
169 'Preprocessor generated incorrectly')
171 def test_mixed_dependencies_list(self):
173 Test that gen_dep() correctly creates dependencies for given
177 dependencies = ['!DEP1', 'DEP2']
178 dep_str = gen_dependencies_one_line(dependencies)
179 self.assertEqual(dep_str, '#if !defined(DEP1) && defined(DEP2)',
180 'Preprocessor generated incorrectly')
182 def test_empty_dependencies_list(self):
184 Test that gen_dep() correctly creates dependencies for given
189 dep_str = gen_dependencies_one_line(dependencies)
190 self.assertEqual(dep_str, '', 'Preprocessor generated incorrectly')
192 def test_large_dependencies_list(self):
194 Test that gen_dep() correctly creates dependencies for given
200 for i in range(count):
201 dependencies.append('DEP%d' % i)
202 dep_str = gen_dependencies_one_line(dependencies)
203 expected = '#if ' + ' && '.join(['defined(%s)' %
204 x for x in dependencies])
205 self.assertEqual(dep_str, expected,
206 'Preprocessor generated incorrectly')
209 class GenFunctionWrapper(TestCase):
211 Test Suite for testing gen_function_wrapper()
214 def test_params_unpack(self):
216 Test that params are properly unpacked in the function call.
220 code = gen_function_wrapper('test_a', '', ('a', 'b', 'c', 'd'))
222 void test_a_wrapper( void ** params )
225 test_a( a, b, c, d );
228 self.assertEqual(code, expected)
230 def test_local(self):
232 Test that params are properly unpacked in the function call.
236 code = gen_function_wrapper('test_a',
237 'int x = 1;', ('x', 'b', 'c', 'd'))
239 void test_a_wrapper( void ** params )
242 test_a( x, b, c, d );
245 self.assertEqual(code, expected)
247 def test_empty_params(self):
249 Test that params are properly unpacked in the function call.
253 code = gen_function_wrapper('test_a', '', ())
255 void test_a_wrapper( void ** params )
262 self.assertEqual(code, expected)
265 class GenDispatch(TestCase):
267 Test suite for testing gen_dispatch()
270 def test_dispatch(self):
272 Test that dispatch table entry is generated correctly.
275 code = gen_dispatch('test_a', ['DEP1', 'DEP2'])
277 #if defined(DEP1) && defined(DEP2)
283 self.assertEqual(code, expected)
285 def test_empty_dependencies(self):
287 Test empty dependency list.
290 code = gen_dispatch('test_a', [])
294 self.assertEqual(code, expected)
297 class StringIOWrapper(StringIO, object):
299 file like class to mock file object in tests.
301 def __init__(self, file_name, data, line_no=0):
309 super(StringIOWrapper, self).__init__(data)
310 self.line_no = line_no
311 self.name = file_name
315 Iterator method. This method overrides base class's
316 next method and extends the next method to count the line
317 numbers as each line is read.
319 :return: Line read from file.
321 parent = super(StringIOWrapper, self)
322 if getattr(parent, 'next', None):
327 line = parent.__next__()
333 def readline(self, length=0):
335 Wrap the base class readline.
340 # pylint: disable=unused-argument
341 line = super(StringIOWrapper, self).readline()
347 class ParseUntilPattern(TestCase):
349 Test Suite for testing parse_until_pattern().
352 def test_suite_headers(self):
354 Test that suite headers are parsed correctly.
358 data = '''#include "mbedtls/ecp.h"
360 #define ECP_PF_UNKNOWN -1
363 expected = '''#line 1 "test_suite_ut.function"
364 #include "mbedtls/ecp.h"
366 #define ECP_PF_UNKNOWN -1
368 stream = StringIOWrapper('test_suite_ut.function', data, line_no=0)
369 headers = parse_until_pattern(stream, END_HEADER_REGEX)
370 self.assertEqual(headers, expected)
372 def test_line_no(self):
374 Test that #line is set to correct line no. in source .function file.
378 data = '''#include "mbedtls/ecp.h"
380 #define ECP_PF_UNKNOWN -1
384 expected = '''#line %d "test_suite_ut.function"
385 #include "mbedtls/ecp.h"
387 #define ECP_PF_UNKNOWN -1
388 ''' % (offset_line_no + 1)
389 stream = StringIOWrapper('test_suite_ut.function', data,
391 headers = parse_until_pattern(stream, END_HEADER_REGEX)
392 self.assertEqual(headers, expected)
394 def test_no_end_header_comment(self):
396 Test that InvalidFileFormat is raised when end header comment is
400 data = '''#include "mbedtls/ecp.h"
402 #define ECP_PF_UNKNOWN -1
405 stream = StringIOWrapper('test_suite_ut.function', data)
406 self.assertRaises(GeneratorInputError, parse_until_pattern, stream,
410 class ParseSuiteDependencies(TestCase):
412 Test Suite for testing parse_suite_dependencies().
415 def test_suite_dependencies(self):
421 * depends_on:MBEDTLS_ECP_C
425 expected = ['MBEDTLS_ECP_C']
426 stream = StringIOWrapper('test_suite_ut.function', data)
427 dependencies = parse_suite_dependencies(stream)
428 self.assertEqual(dependencies, expected)
430 def test_no_end_dep_comment(self):
432 Test that InvalidFileFormat is raised when end dep comment is missing.
436 * depends_on:MBEDTLS_ECP_C
438 stream = StringIOWrapper('test_suite_ut.function', data)
439 self.assertRaises(GeneratorInputError, parse_suite_dependencies,
442 def test_dependencies_split(self):
444 Test that InvalidFileFormat is raised when end dep comment is missing.
448 * depends_on:MBEDTLS_ECP_C:A:B: C : D :F : G: !H
452 expected = ['MBEDTLS_ECP_C', 'A', 'B', 'C', 'D', 'F', 'G', '!H']
453 stream = StringIOWrapper('test_suite_ut.function', data)
454 dependencies = parse_suite_dependencies(stream)
455 self.assertEqual(dependencies, expected)
458 class ParseFuncDependencies(TestCase):
460 Test Suite for testing parse_function_dependencies()
463 def test_function_dependencies(self):
465 Test that parse_function_dependencies() correctly parses function
469 line = '/* BEGIN_CASE ' \
470 'depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */'
471 expected = ['MBEDTLS_ENTROPY_NV_SEED', 'MBEDTLS_FS_IO']
472 dependencies = parse_function_dependencies(line)
473 self.assertEqual(dependencies, expected)
475 def test_no_dependencies(self):
477 Test that parse_function_dependencies() correctly parses function
481 line = '/* BEGIN_CASE */'
482 dependencies = parse_function_dependencies(line)
483 self.assertEqual(dependencies, [])
485 def test_tolerance(self):
487 Test that parse_function_dependencies() correctly parses function
491 line = '/* BEGIN_CASE depends_on:MBEDTLS_FS_IO: A : !B:C : F*/'
492 dependencies = parse_function_dependencies(line)
493 self.assertEqual(dependencies, ['MBEDTLS_FS_IO', 'A', '!B', 'C', 'F'])
496 class ParseFuncSignature(TestCase):
498 Test Suite for parse_function_arguments().
501 def test_int_and_char_params(self):
503 Test int and char parameters parsing
506 line = 'void entropy_threshold( char * a, int b, int result )'
507 args, local, arg_dispatch = parse_function_arguments(line)
508 self.assertEqual(args, ['char*', 'int', 'int'])
509 self.assertEqual(local, '')
510 self.assertEqual(arg_dispatch, ['(char *) params[0]',
511 '*( (int *) params[1] )',
512 '*( (int *) params[2] )'])
514 def test_hex_params(self):
516 Test hex parameters parsing
519 line = 'void entropy_threshold( char * a, data_t * h, int result )'
520 args, local, arg_dispatch = parse_function_arguments(line)
521 self.assertEqual(args, ['char*', 'hex', 'int'])
522 self.assertEqual(local,
523 ' data_t data1 = {(uint8_t *) params[1], '
524 '*( (uint32_t *) params[2] )};\n')
525 self.assertEqual(arg_dispatch, ['(char *) params[0]',
527 '*( (int *) params[3] )'])
529 def test_unsupported_arg(self):
531 Test unsupported arguments (not among int, char * and data_t)
534 line = 'void entropy_threshold( char * a, data_t * h, char result )'
535 self.assertRaises(ValueError, parse_function_arguments, line)
537 def test_no_params(self):
542 line = 'void entropy_threshold()'
543 args, local, arg_dispatch = parse_function_arguments(line)
544 self.assertEqual(args, [])
545 self.assertEqual(local, '')
546 self.assertEqual(arg_dispatch, [])
549 class ParseFunctionCode(TestCase):
551 Test suite for testing parse_function_code()
554 def assert_raises_regex(self, exp, regex, func, *args):
556 Python 2 & 3 portable wrapper of assertRaisesRegex(p)? function.
558 :param exp: Exception type expected to be raised by cb.
559 :param regex: Expected exception message
560 :param func: callable object under test
561 :param args: variable positional arguments
563 parent = super(ParseFunctionCode, self)
565 # Pylint does not appreciate that the super method called
566 # conditionally can be available in other Python version
567 # then that of Pylint.
568 # Workaround is to call the method via getattr.
569 # Pylint ignores that the method got via getattr is
570 # conditionally executed. Method has to be a callable.
571 # Hence, using a dummy callable for getattr default.
572 dummy = lambda *x: None
573 # First Python 3 assertRaisesRegex is checked, since Python 2
574 # assertRaisesRegexp is also available in Python 3 but is
576 for name in ('assertRaisesRegex', 'assertRaisesRegexp'):
577 method = getattr(parent, name, dummy)
578 if method is not dummy:
579 method(exp, regex, func, *args)
582 raise AttributeError(" 'ParseFunctionCode' object has no attribute"
583 " 'assertRaisesRegex' or 'assertRaisesRegexp'"
586 def test_no_function(self):
588 Test no test function found.
596 stream = StringIOWrapper('test_suite_ut.function', data)
597 err_msg = 'file: test_suite_ut.function - Test functions not found!'
598 self.assert_raises_regex(GeneratorInputError, err_msg,
599 parse_function_code, stream, [], [])
601 def test_no_end_case_comment(self):
603 Test missing end case.
611 stream = StringIOWrapper('test_suite_ut.function', data)
612 err_msg = r'file: test_suite_ut.function - '\
613 'end case pattern .*? not found!'
614 self.assert_raises_regex(GeneratorInputError, err_msg,
615 parse_function_code, stream, [], [])
617 @patch("generate_test_code.parse_function_arguments")
618 def test_function_called(self,
619 parse_function_arguments_mock):
621 Test parse_function_code()
624 parse_function_arguments_mock.return_value = ([], '', [])
630 stream = StringIOWrapper('test_suite_ut.function', data)
631 self.assertRaises(GeneratorInputError, parse_function_code,
633 self.assertTrue(parse_function_arguments_mock.called)
634 parse_function_arguments_mock.assert_called_with('void test_func()\n')
636 @patch("generate_test_code.gen_dispatch")
637 @patch("generate_test_code.gen_dependencies")
638 @patch("generate_test_code.gen_function_wrapper")
639 @patch("generate_test_code.parse_function_arguments")
640 def test_return(self, parse_function_arguments_mock,
641 gen_function_wrapper_mock,
642 gen_dependencies_mock,
648 parse_function_arguments_mock.return_value = ([], '', [])
649 gen_function_wrapper_mock.return_value = ''
650 gen_dependencies_mock.side_effect = gen_dependencies
651 gen_dispatch_mock.side_effect = gen_dispatch
660 stream = StringIOWrapper('test_suite_ut.function', data)
661 name, arg, code, dispatch_code = parse_function_code(stream, [], [])
663 self.assertTrue(parse_function_arguments_mock.called)
664 parse_function_arguments_mock.assert_called_with('void func()\n')
665 gen_function_wrapper_mock.assert_called_with('test_func', '', [])
666 self.assertEqual(name, 'test_func')
667 self.assertEqual(arg, [])
668 expected = '''#line 1 "test_suite_ut.function"
678 self.assertEqual(code, expected)
679 self.assertEqual(dispatch_code, "\n test_func_wrapper,\n")
681 @patch("generate_test_code.gen_dispatch")
682 @patch("generate_test_code.gen_dependencies")
683 @patch("generate_test_code.gen_function_wrapper")
684 @patch("generate_test_code.parse_function_arguments")
685 def test_with_exit_label(self, parse_function_arguments_mock,
686 gen_function_wrapper_mock,
687 gen_dependencies_mock,
690 Test when exit label is present.
693 parse_function_arguments_mock.return_value = ([], '', [])
694 gen_function_wrapper_mock.return_value = ''
695 gen_dependencies_mock.side_effect = gen_dependencies
696 gen_dispatch_mock.side_effect = gen_dispatch
708 stream = StringIOWrapper('test_suite_ut.function', data)
709 _, _, code, _ = parse_function_code(stream, [], [])
711 expected = '''#line 1 "test_suite_ut.function"
722 self.assertEqual(code, expected)
724 def test_non_void_function(self):
726 Test invalid signature (non void).
729 data = 'int entropy_threshold( char * a, data_t * h, int result )'
730 err_msg = 'file: test_suite_ut.function - Test functions not found!'
731 stream = StringIOWrapper('test_suite_ut.function', data)
732 self.assert_raises_regex(GeneratorInputError, err_msg,
733 parse_function_code, stream, [], [])
735 @patch("generate_test_code.gen_dispatch")
736 @patch("generate_test_code.gen_dependencies")
737 @patch("generate_test_code.gen_function_wrapper")
738 @patch("generate_test_code.parse_function_arguments")
739 def test_functio_name_on_newline(self, parse_function_arguments_mock,
740 gen_function_wrapper_mock,
741 gen_dependencies_mock,
744 Test when exit label is present.
747 parse_function_arguments_mock.return_value = ([], '', [])
748 gen_function_wrapper_mock.return_value = ''
749 gen_dependencies_mock.side_effect = gen_dependencies
750 gen_dispatch_mock.side_effect = gen_dispatch
765 stream = StringIOWrapper('test_suite_ut.function', data)
766 _, _, code, _ = parse_function_code(stream, [], [])
768 expected = '''#line 1 "test_suite_ut.function"
782 self.assertEqual(code, expected)
785 class ParseFunction(TestCase):
787 Test Suite for testing parse_functions()
790 @patch("generate_test_code.parse_until_pattern")
791 def test_begin_header(self, parse_until_pattern_mock):
793 Test that begin header is checked and parse_until_pattern() is called.
797 """Stop when parse_until_pattern is called."""
799 parse_until_pattern_mock.side_effect = stop
800 data = '''/* BEGIN_HEADER */
801 #include "mbedtls/ecp.h"
803 #define ECP_PF_UNKNOWN -1
806 stream = StringIOWrapper('test_suite_ut.function', data)
807 self.assertRaises(Exception, parse_functions, stream)
808 parse_until_pattern_mock.assert_called_with(stream, END_HEADER_REGEX)
809 self.assertEqual(stream.line_no, 1)
811 @patch("generate_test_code.parse_until_pattern")
812 def test_begin_helper(self, parse_until_pattern_mock):
814 Test that begin helper is checked and parse_until_pattern() is called.
818 """Stop when parse_until_pattern is called."""
820 parse_until_pattern_mock.side_effect = stop
821 data = '''/* BEGIN_SUITE_HELPERS */
822 void print_hello_world()
824 printf("Hello World!\n");
826 /* END_SUITE_HELPERS */
828 stream = StringIOWrapper('test_suite_ut.function', data)
829 self.assertRaises(Exception, parse_functions, stream)
830 parse_until_pattern_mock.assert_called_with(stream,
831 END_SUITE_HELPERS_REGEX)
832 self.assertEqual(stream.line_no, 1)
834 @patch("generate_test_code.parse_suite_dependencies")
835 def test_begin_dep(self, parse_suite_dependencies_mock):
837 Test that begin dep is checked and parse_suite_dependencies() is
842 """Stop when parse_until_pattern is called."""
844 parse_suite_dependencies_mock.side_effect = stop
845 data = '''/* BEGIN_DEPENDENCIES
846 * depends_on:MBEDTLS_ECP_C
850 stream = StringIOWrapper('test_suite_ut.function', data)
851 self.assertRaises(Exception, parse_functions, stream)
852 parse_suite_dependencies_mock.assert_called_with(stream)
853 self.assertEqual(stream.line_no, 1)
855 @patch("generate_test_code.parse_function_dependencies")
856 def test_begin_function_dep(self, func_mock):
858 Test that begin dep is checked and parse_function_dependencies() is
863 """Stop when parse_until_pattern is called."""
865 func_mock.side_effect = stop
867 dependencies_str = '/* BEGIN_CASE ' \
868 'depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */\n'
869 data = '''%svoid test_func()
872 ''' % dependencies_str
873 stream = StringIOWrapper('test_suite_ut.function', data)
874 self.assertRaises(Exception, parse_functions, stream)
875 func_mock.assert_called_with(dependencies_str)
876 self.assertEqual(stream.line_no, 1)
878 @patch("generate_test_code.parse_function_code")
879 @patch("generate_test_code.parse_function_dependencies")
880 def test_return(self, func_mock1, func_mock2):
882 Test that begin case is checked and parse_function_code() is called.
885 func_mock1.return_value = []
886 in_func_code = '''void test_func()
893 func_mock2.return_value = 'test_func', [],\
894 in_func_code, func_dispatch
895 dependencies_str = '/* BEGIN_CASE ' \
896 'depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */\n'
897 data = '''%svoid test_func()
900 ''' % dependencies_str
901 stream = StringIOWrapper('test_suite_ut.function', data)
902 suite_dependencies, dispatch_code, func_code, func_info = \
903 parse_functions(stream)
904 func_mock1.assert_called_with(dependencies_str)
905 func_mock2.assert_called_with(stream, [], [])
906 self.assertEqual(stream.line_no, 5)
907 self.assertEqual(suite_dependencies, [])
908 expected_dispatch_code = '''/* Function Id: 0 */
912 self.assertEqual(dispatch_code, expected_dispatch_code)
913 self.assertEqual(func_code, in_func_code)
914 self.assertEqual(func_info, {'test_func': (0, [])})
916 def test_parsing(self):
921 data = '''/* BEGIN_HEADER */
922 #include "mbedtls/ecp.h"
924 #define ECP_PF_UNKNOWN -1
927 /* BEGIN_DEPENDENCIES
928 * depends_on:MBEDTLS_ECP_C
932 /* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
938 /* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
944 stream = StringIOWrapper('test_suite_ut.function', data)
945 suite_dependencies, dispatch_code, func_code, func_info = \
946 parse_functions(stream)
947 self.assertEqual(stream.line_no, 23)
948 self.assertEqual(suite_dependencies, ['MBEDTLS_ECP_C'])
950 expected_dispatch_code = '''/* Function Id: 0 */
952 #if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_ENTROPY_NV_SEED) && defined(MBEDTLS_FS_IO)
959 #if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_ENTROPY_NV_SEED) && defined(MBEDTLS_FS_IO)
965 self.assertEqual(dispatch_code, expected_dispatch_code)
966 expected_func_code = '''#if defined(MBEDTLS_ECP_C)
967 #line 2 "test_suite_ut.function"
968 #include "mbedtls/ecp.h"
970 #define ECP_PF_UNKNOWN -1
971 #if defined(MBEDTLS_ENTROPY_NV_SEED)
972 #if defined(MBEDTLS_FS_IO)
973 #line 13 "test_suite_ut.function"
980 void test_func1_wrapper( void ** params )
986 #endif /* MBEDTLS_FS_IO */
987 #endif /* MBEDTLS_ENTROPY_NV_SEED */
988 #if defined(MBEDTLS_ENTROPY_NV_SEED)
989 #if defined(MBEDTLS_FS_IO)
990 #line 19 "test_suite_ut.function"
997 void test_func2_wrapper( void ** params )
1003 #endif /* MBEDTLS_FS_IO */
1004 #endif /* MBEDTLS_ENTROPY_NV_SEED */
1005 #endif /* MBEDTLS_ECP_C */
1007 self.assertEqual(func_code, expected_func_code)
1008 self.assertEqual(func_info, {'test_func1': (0, []),
1009 'test_func2': (1, [])})
1011 def test_same_function_name(self):
1016 data = '''/* BEGIN_HEADER */
1017 #include "mbedtls/ecp.h"
1019 #define ECP_PF_UNKNOWN -1
1022 /* BEGIN_DEPENDENCIES
1023 * depends_on:MBEDTLS_ECP_C
1027 /* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
1033 /* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
1039 stream = StringIOWrapper('test_suite_ut.function', data)
1040 self.assertRaises(GeneratorInputError, parse_functions, stream)
1043 class EscapedSplit(TestCase):
1045 Test suite for testing escaped_split().
1046 Note: Since escaped_split() output is used to write back to the
1047 intermediate data file. Any escape characters in the input are
1048 retained in the output.
1051 def test_invalid_input(self):
1053 Test when input split character is not a character.
1056 self.assertRaises(ValueError, escaped_split, '', 'string')
1058 def test_empty_string(self):
1060 Test empty string input.
1063 splits = escaped_split('', ':')
1064 self.assertEqual(splits, [])
1066 def test_no_escape(self):
1068 Test with no escape character. The behaviour should be same as
1072 test_str = 'yahoo:google'
1073 splits = escaped_split(test_str, ':')
1074 self.assertEqual(splits, test_str.split(':'))
1076 def test_escaped_input(self):
1078 Test input that has escaped delimiter.
1081 test_str = r'yahoo\:google:facebook'
1082 splits = escaped_split(test_str, ':')
1083 self.assertEqual(splits, [r'yahoo\:google', 'facebook'])
1085 def test_escaped_escape(self):
1087 Test input that has escaped delimiter.
1090 test_str = r'yahoo\\:google:facebook'
1091 splits = escaped_split(test_str, ':')
1092 self.assertEqual(splits, [r'yahoo\\', 'google', 'facebook'])
1094 def test_all_at_once(self):
1096 Test input that has escaped delimiter.
1099 test_str = r'yahoo\\:google:facebook\:instagram\\:bbc\\:wikipedia'
1100 splits = escaped_split(test_str, ':')
1101 self.assertEqual(splits, [r'yahoo\\', r'google',
1102 r'facebook\:instagram\\',
1103 r'bbc\\', r'wikipedia'])
1106 class ParseTestData(TestCase):
1108 Test suite for parse test data.
1111 def test_parser(self):
1113 Test that tests are parsed correctly from data file.
1117 Diffie-Hellman full exchange #1
1118 dhm_do_dhm:10:"23":10:"5"
1120 Diffie-Hellman full exchange #2
1121 dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622"
1123 Diffie-Hellman full exchange #3
1124 dhm_do_dhm:10:"9345098382739712938719287391879381271":10:"9345098792137312973297123912791271"
1126 Diffie-Hellman selftest
1129 stream = StringIOWrapper('test_suite_ut.function', data)
1130 tests = [(name, test_function, dependencies, args)
1131 for name, test_function, dependencies, args in
1132 parse_test_data(stream)]
1133 test1, test2, test3, test4 = tests
1134 self.assertEqual(test1[0], 'Diffie-Hellman full exchange #1')
1135 self.assertEqual(test1[1], 'dhm_do_dhm')
1136 self.assertEqual(test1[2], [])
1137 self.assertEqual(test1[3], ['10', '"23"', '10', '"5"'])
1139 self.assertEqual(test2[0], 'Diffie-Hellman full exchange #2')
1140 self.assertEqual(test2[1], 'dhm_do_dhm')
1141 self.assertEqual(test2[2], [])
1142 self.assertEqual(test2[3], ['10', '"93450983094850938450983409623"',
1143 '10', '"9345098304850938450983409622"'])
1145 self.assertEqual(test3[0], 'Diffie-Hellman full exchange #3')
1146 self.assertEqual(test3[1], 'dhm_do_dhm')
1147 self.assertEqual(test3[2], [])
1148 self.assertEqual(test3[3], ['10',
1149 '"9345098382739712938719287391879381271"',
1151 '"9345098792137312973297123912791271"'])
1153 self.assertEqual(test4[0], 'Diffie-Hellman selftest')
1154 self.assertEqual(test4[1], 'dhm_selftest')
1155 self.assertEqual(test4[2], [])
1156 self.assertEqual(test4[3], [])
1158 def test_with_dependencies(self):
1160 Test that tests with dependencies are parsed.
1164 Diffie-Hellman full exchange #1
1166 dhm_do_dhm:10:"23":10:"5"
1168 Diffie-Hellman full exchange #2
1169 dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622"
1172 stream = StringIOWrapper('test_suite_ut.function', data)
1173 tests = [(name, function_name, dependencies, args)
1174 for name, function_name, dependencies, args in
1175 parse_test_data(stream)]
1176 test1, test2 = tests
1177 self.assertEqual(test1[0], 'Diffie-Hellman full exchange #1')
1178 self.assertEqual(test1[1], 'dhm_do_dhm')
1179 self.assertEqual(test1[2], ['YAHOO'])
1180 self.assertEqual(test1[3], ['10', '"23"', '10', '"5"'])
1182 self.assertEqual(test2[0], 'Diffie-Hellman full exchange #2')
1183 self.assertEqual(test2[1], 'dhm_do_dhm')
1184 self.assertEqual(test2[2], [])
1185 self.assertEqual(test2[3], ['10', '"93450983094850938450983409623"',
1186 '10', '"9345098304850938450983409622"'])
1188 def test_no_args(self):
1190 Test GeneratorInputError is raised when test function name and
1191 args line is missing.
1195 Diffie-Hellman full exchange #1
1199 Diffie-Hellman full exchange #2
1200 dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622"
1203 stream = StringIOWrapper('test_suite_ut.function', data)
1206 for _, _, _, _ in parse_test_data(stream):
1208 except GeneratorInputError as err:
1209 self.assertEqual(type(err), GeneratorInputError)
1211 def test_incomplete_data(self):
1213 Test GeneratorInputError is raised when test function name
1214 and args line is missing.
1218 Diffie-Hellman full exchange #1
1221 stream = StringIOWrapper('test_suite_ut.function', data)
1224 for _, _, _, _ in parse_test_data(stream):
1226 except GeneratorInputError as err:
1227 self.assertEqual(type(err), GeneratorInputError)
1230 class GenDepCheck(TestCase):
1232 Test suite for gen_dep_check(). It is assumed this function is
1233 called with valid inputs.
1236 def test_gen_dep_check(self):
1238 Test that dependency check code generated correctly.
1245 ret = DEPENDENCY_SUPPORTED;
1247 ret = DEPENDENCY_NOT_SUPPORTED;
1251 out = gen_dep_check(5, 'YAHOO')
1252 self.assertEqual(out, expected)
1254 def test_not_defined_dependency(self):
1256 Test dependency with !.
1263 ret = DEPENDENCY_SUPPORTED;
1265 ret = DEPENDENCY_NOT_SUPPORTED;
1269 out = gen_dep_check(5, '!YAHOO')
1270 self.assertEqual(out, expected)
1272 def test_empty_dependency(self):
1274 Test invalid dependency input.
1277 self.assertRaises(GeneratorInputError, gen_dep_check, 5, '!')
1279 def test_negative_dep_id(self):
1281 Test invalid dependency input.
1284 self.assertRaises(GeneratorInputError, gen_dep_check, -1, 'YAHOO')
1287 class GenExpCheck(TestCase):
1289 Test suite for gen_expression_check(). It is assumed this function
1290 is called with valid inputs.
1293 def test_gen_exp_check(self):
1295 Test that expression check code generated correctly.
1304 out = gen_expression_check(5, 'YAHOO')
1305 self.assertEqual(out, expected)
1307 def test_invalid_expression(self):
1309 Test invalid expression input.
1312 self.assertRaises(GeneratorInputError, gen_expression_check, 5, '')
1314 def test_negative_exp_id(self):
1316 Test invalid expression id.
1319 self.assertRaises(GeneratorInputError, gen_expression_check,
1323 class WriteDependencies(TestCase):
1325 Test suite for testing write_dependencies.
1328 def test_no_test_dependencies(self):
1330 Test when test dependencies input is empty.
1333 stream = StringIOWrapper('test_suite_ut.data', '')
1334 unique_dependencies = []
1335 dep_check_code = write_dependencies(stream, [], unique_dependencies)
1336 self.assertEqual(dep_check_code, '')
1337 self.assertEqual(len(unique_dependencies), 0)
1338 self.assertEqual(stream.getvalue(), '')
1340 def test_unique_dep_ids(self):
1345 stream = StringIOWrapper('test_suite_ut.data', '')
1346 unique_dependencies = []
1347 dep_check_code = write_dependencies(stream, ['DEP3', 'DEP2', 'DEP1'],
1348 unique_dependencies)
1349 expect_dep_check_code = '''
1353 ret = DEPENDENCY_SUPPORTED;
1355 ret = DEPENDENCY_NOT_SUPPORTED;
1362 ret = DEPENDENCY_SUPPORTED;
1364 ret = DEPENDENCY_NOT_SUPPORTED;
1371 ret = DEPENDENCY_SUPPORTED;
1373 ret = DEPENDENCY_NOT_SUPPORTED;
1377 self.assertEqual(dep_check_code, expect_dep_check_code)
1378 self.assertEqual(len(unique_dependencies), 3)
1379 self.assertEqual(stream.getvalue(), 'depends_on:0:1:2\n')
1381 def test_dep_id_repeat(self):
1386 stream = StringIOWrapper('test_suite_ut.data', '')
1387 unique_dependencies = []
1389 dep_check_code += write_dependencies(stream, ['DEP3', 'DEP2'],
1390 unique_dependencies)
1391 dep_check_code += write_dependencies(stream, ['DEP2', 'DEP1'],
1392 unique_dependencies)
1393 dep_check_code += write_dependencies(stream, ['DEP1', 'DEP3'],
1394 unique_dependencies)
1395 expect_dep_check_code = '''
1399 ret = DEPENDENCY_SUPPORTED;
1401 ret = DEPENDENCY_NOT_SUPPORTED;
1408 ret = DEPENDENCY_SUPPORTED;
1410 ret = DEPENDENCY_NOT_SUPPORTED;
1417 ret = DEPENDENCY_SUPPORTED;
1419 ret = DEPENDENCY_NOT_SUPPORTED;
1423 self.assertEqual(dep_check_code, expect_dep_check_code)
1424 self.assertEqual(len(unique_dependencies), 3)
1425 self.assertEqual(stream.getvalue(),
1426 'depends_on:0:1\ndepends_on:1:2\ndepends_on:2:0\n')
1429 class WriteParams(TestCase):
1431 Test Suite for testing write_parameters().
1434 def test_no_params(self):
1436 Test with empty test_args
1439 stream = StringIOWrapper('test_suite_ut.data', '')
1440 unique_expressions = []
1441 expression_code = write_parameters(stream, [], [], unique_expressions)
1442 self.assertEqual(len(unique_expressions), 0)
1443 self.assertEqual(expression_code, '')
1444 self.assertEqual(stream.getvalue(), '\n')
1446 def test_no_exp_param(self):
1448 Test when there is no macro or expression in the params.
1451 stream = StringIOWrapper('test_suite_ut.data', '')
1452 unique_expressions = []
1453 expression_code = write_parameters(stream, ['"Yahoo"', '"abcdef00"',
1455 ['char*', 'hex', 'int'],
1457 self.assertEqual(len(unique_expressions), 0)
1458 self.assertEqual(expression_code, '')
1459 self.assertEqual(stream.getvalue(),
1460 ':char*:"Yahoo":hex:"abcdef00":int:0\n')
1462 def test_hex_format_int_param(self):
1464 Test int parameter in hex format.
1467 stream = StringIOWrapper('test_suite_ut.data', '')
1468 unique_expressions = []
1469 expression_code = write_parameters(stream,
1470 ['"Yahoo"', '"abcdef00"', '0xAA'],
1471 ['char*', 'hex', 'int'],
1473 self.assertEqual(len(unique_expressions), 0)
1474 self.assertEqual(expression_code, '')
1475 self.assertEqual(stream.getvalue(),
1476 ':char*:"Yahoo":hex:"abcdef00":int:0xAA\n')
1478 def test_with_exp_param(self):
1480 Test when there is macro or expression in the params.
1483 stream = StringIOWrapper('test_suite_ut.data', '')
1484 unique_expressions = []
1485 expression_code = write_parameters(stream,
1486 ['"Yahoo"', '"abcdef00"', '0',
1487 'MACRO1', 'MACRO2', 'MACRO3'],
1488 ['char*', 'hex', 'int',
1489 'int', 'int', 'int'],
1491 self.assertEqual(len(unique_expressions), 3)
1492 self.assertEqual(unique_expressions, ['MACRO1', 'MACRO2', 'MACRO3'])
1493 expected_expression_code = '''
1496 *out_value = MACRO1;
1501 *out_value = MACRO2;
1506 *out_value = MACRO3;
1509 self.assertEqual(expression_code, expected_expression_code)
1510 self.assertEqual(stream.getvalue(),
1511 ':char*:"Yahoo":hex:"abcdef00":int:0:exp:0:exp:1'
1514 def test_with_repeat_calls(self):
1516 Test when write_parameter() is called with same macro or expression.
1519 stream = StringIOWrapper('test_suite_ut.data', '')
1520 unique_expressions = []
1521 expression_code = ''
1522 expression_code += write_parameters(stream,
1523 ['"Yahoo"', 'MACRO1', 'MACRO2'],
1524 ['char*', 'int', 'int'],
1526 expression_code += write_parameters(stream,
1527 ['"abcdef00"', 'MACRO2', 'MACRO3'],
1528 ['hex', 'int', 'int'],
1530 expression_code += write_parameters(stream,
1531 ['0', 'MACRO3', 'MACRO1'],
1532 ['int', 'int', 'int'],
1534 self.assertEqual(len(unique_expressions), 3)
1535 self.assertEqual(unique_expressions, ['MACRO1', 'MACRO2', 'MACRO3'])
1536 expected_expression_code = '''
1539 *out_value = MACRO1;
1544 *out_value = MACRO2;
1549 *out_value = MACRO3;
1552 self.assertEqual(expression_code, expected_expression_code)
1553 expected_data_file = ''':char*:"Yahoo":exp:0:exp:1
1554 :hex:"abcdef00":exp:1:exp:2
1557 self.assertEqual(stream.getvalue(), expected_data_file)
1560 class GenTestSuiteDependenciesChecks(TestCase):
1562 Test suite for testing gen_suite_dep_checks()
1564 def test_empty_suite_dependencies(self):
1566 Test with empty suite_dependencies list.
1570 dep_check_code, expression_code = \
1571 gen_suite_dep_checks([], 'DEP_CHECK_CODE', 'EXPRESSION_CODE')
1572 self.assertEqual(dep_check_code, 'DEP_CHECK_CODE')
1573 self.assertEqual(expression_code, 'EXPRESSION_CODE')
1575 def test_suite_dependencies(self):
1577 Test with suite_dependencies list.
1581 dep_check_code, expression_code = \
1582 gen_suite_dep_checks(['SUITE_DEP'], 'DEP_CHECK_CODE',
1584 expected_dep_check_code = '''
1585 #if defined(SUITE_DEP)
1589 expected_expression_code = '''
1590 #if defined(SUITE_DEP)
1594 self.assertEqual(dep_check_code, expected_dep_check_code)
1595 self.assertEqual(expression_code, expected_expression_code)
1597 def test_no_dep_no_exp(self):
1599 Test when there are no dependency and expression code.
1602 dep_check_code, expression_code = gen_suite_dep_checks([], '', '')
1603 self.assertEqual(dep_check_code, '')
1604 self.assertEqual(expression_code, '')
1607 class GenFromTestData(TestCase):
1609 Test suite for gen_from_test_data()
1613 @patch("generate_test_code.write_dependencies")
1614 @patch("generate_test_code.write_parameters")
1615 @patch("generate_test_code.gen_suite_dep_checks")
1616 def test_intermediate_data_file(func_mock1,
1617 write_parameters_mock,
1618 write_dependencies_mock):
1620 Test that intermediate data file is written with expected data.
1628 data_f = StringIOWrapper('test_suite_ut.data', data)
1629 out_data_f = StringIOWrapper('test_suite_ut.datax', '')
1630 func_info = {'test_func1': (1, ('int',))}
1631 suite_dependencies = []
1632 write_parameters_mock.side_effect = write_parameters
1633 write_dependencies_mock.side_effect = write_dependencies
1634 func_mock1.side_effect = gen_suite_dep_checks
1635 gen_from_test_data(data_f, out_data_f, func_info, suite_dependencies)
1636 write_dependencies_mock.assert_called_with(out_data_f,
1638 write_parameters_mock.assert_called_with(out_data_f, ['0'],
1640 expected_dep_check_code = '''
1644 ret = DEPENDENCY_SUPPORTED;
1646 ret = DEPENDENCY_NOT_SUPPORTED;
1650 func_mock1.assert_called_with(
1651 suite_dependencies, expected_dep_check_code, '')
1653 def test_function_not_found(self):
1655 Test that AssertError is raised when function info in not found.
1663 data_f = StringIOWrapper('test_suite_ut.data', data)
1664 out_data_f = StringIOWrapper('test_suite_ut.datax', '')
1665 func_info = {'test_func2': (1, ('int',))}
1666 suite_dependencies = []
1667 self.assertRaises(GeneratorInputError, gen_from_test_data,
1668 data_f, out_data_f, func_info, suite_dependencies)
1670 def test_different_func_args(self):
1672 Test that AssertError is raised when no. of parameters and
1673 function args differ.
1681 data_f = StringIOWrapper('test_suite_ut.data', data)
1682 out_data_f = StringIOWrapper('test_suite_ut.datax', '')
1683 func_info = {'test_func2': (1, ('int', 'hex'))}
1684 suite_dependencies = []
1685 self.assertRaises(GeneratorInputError, gen_from_test_data, data_f,
1686 out_data_f, func_info, suite_dependencies)
1688 def test_output(self):
1690 Test that intermediate data file is written with expected data.
1696 func1:0:0xfa:MACRO1:MACRO2
1699 depends_on:DEP1:DEP2
1700 func2:"yahoo":88:MACRO1
1702 data_f = StringIOWrapper('test_suite_ut.data', data)
1703 out_data_f = StringIOWrapper('test_suite_ut.datax', '')
1704 func_info = {'test_func1': (0, ('int', 'int', 'int', 'int')),
1705 'test_func2': (1, ('char*', 'int', 'int'))}
1706 suite_dependencies = []
1707 dep_check_code, expression_code = \
1708 gen_from_test_data(data_f, out_data_f, func_info,
1710 expected_dep_check_code = '''
1714 ret = DEPENDENCY_SUPPORTED;
1716 ret = DEPENDENCY_NOT_SUPPORTED;
1723 ret = DEPENDENCY_SUPPORTED;
1725 ret = DEPENDENCY_NOT_SUPPORTED;
1729 expected_data = '''My test 1
1731 0:int:0:int:0xfa:exp:0:exp:1
1735 1:char*:"yahoo":int:88:exp:0
1738 expected_expression_code = '''
1741 *out_value = MACRO1;
1746 *out_value = MACRO2;
1749 self.assertEqual(dep_check_code, expected_dep_check_code)
1750 self.assertEqual(out_data_f.getvalue(), expected_data)
1751 self.assertEqual(expression_code, expected_expression_code)
1754 if __name__ == '__main__':