Make test function parsing robust

This commit enhances parsing of the test function in generate_test_code.py for
cases where return type and function name are on separate lines.
diff --git a/tests/scripts/generate_test_code.py b/tests/scripts/generate_test_code.py
index b744d7c..b01bd35 100755
--- a/tests/scripts/generate_test_code.py
+++ b/tests/scripts/generate_test_code.py
@@ -185,11 +185,10 @@
 
 DEPENDENCY_REGEX = r'depends_on:(?P<dependencies>.*)'
 C_IDENTIFIER_REGEX = r'!?[a-z_][a-z0-9_]*'
-TEST_FUNCTION_VALIDATION_REGEX = r'\s*void\s+(\w+)\s*\('
+TEST_FUNCTION_VALIDATION_REGEX = r'\s*void\s+(?P<func_name>\w+)\s*\('
 INT_CHECK_REGEX = r'int\s+.*'
 CHAR_CHECK_REGEX = r'char\s*\*\s*.*'
 DATA_T_CHECK_REGEX = r'data_t\s*\*\s*.*'
-FUNCTION_ARG_LIST_START_REGEX = r'.*?\s+(\w+)\s*\('
 FUNCTION_ARG_LIST_END_REGEX = r'.*\)'
 EXIT_LABEL_REGEX = r'^exit:'
 
@@ -451,7 +450,7 @@
     return dependencies
 
 
-def parse_function_signature(line):
+def parse_function_arguments(line):
     """
     Parses test function signature for validation and generates
     a dispatch wrapper function that translates input test vectors
@@ -459,19 +458,15 @@
 
     :param line: Line from .function file that has a function
                  signature.
-    :return: function name, argument list, local variables for
+    :return: argument list, local variables for
              wrapper function and argument dispatch code.
     """
     args = []
     local_vars = ''
     args_dispatch = []
-    # Check if the test function returns void.
-    match = re.search(TEST_FUNCTION_VALIDATION_REGEX, line, re.I)
-    if not match:
-        raise ValueError("Test function should return 'void'\n%s" % line)
-    name = match.group(1)
-    line = line[len(match.group(0)):]
     arg_idx = 0
+    # Remove characters before arguments
+    line = line[line.find('(') + 1:]
     # Process arguments, ex: <type> arg1, <type> arg2 )
     # This script assumes that the argument list is terminated by ')'
     # i.e. the test functions will not have a function pointer
@@ -501,7 +496,7 @@
                              "'char *' or 'data_t'\n%s" % line)
         arg_idx += 1
 
-    return name, args, local_vars, args_dispatch
+    return args, local_vars, args_dispatch
 
 
 def parse_function_code(funcs_f, dependencies, suite_dependencies):
@@ -514,30 +509,38 @@
     :param suite_dependencies: List of test suite dependencies
     :return: Function name, arguments, function code and dispatch code.
     """
-    code = '#line %d "%s"\n' % (funcs_f.line_no + 1, funcs_f.name)
+    line_directive = '#line %d "%s"\n' % (funcs_f.line_no + 1, funcs_f.name)
+    code = ''
     has_exit_label = False
     for line in funcs_f:
-        # Check function signature. This script expects function name
-        # and return type to be specified at the same line.
-        match = re.match(FUNCTION_ARG_LIST_START_REGEX, line, re.I)
+        # Check function signature. Function signature may be split
+        # across multiple lines. Here we try to find the start of
+        # arguments list, then remove '\n's and apply the regex to
+        # detect function start.
+        up_to_arg_list_start = code + line[:line.find('(') + 1]
+        match = re.match(TEST_FUNCTION_VALIDATION_REGEX,
+                         up_to_arg_list_start.replace('\n', ' '), re.I)
         if match:
             # check if we have full signature i.e. split in more lines
+            name = match.group('func_name')
             if not re.match(FUNCTION_ARG_LIST_END_REGEX, line):
                 for lin in funcs_f:
                     line += lin
                     if re.search(FUNCTION_ARG_LIST_END_REGEX, line):
                         break
-            name, args, local_vars, args_dispatch = parse_function_signature(
+            args, local_vars, args_dispatch = parse_function_arguments(
                 line)
-            code += line.replace(name, 'test_' + name, 1)
-            name = 'test_' + name
-            break
-        else:
             code += line
+            break
+        code += line
     else:
         raise GeneratorInputError("file: %s - Test functions not found!" %
                                   funcs_f.name)
 
+    # Prefix test function name with 'test_'
+    code = code.replace(name, 'test_' + name, 1)
+    name = 'test_' + name
+
     for line in funcs_f:
         if re.search(END_CASE_REGEX, line):
             break
@@ -557,7 +560,8 @@
     ;
 }""".join(split_code)
 
-    code += gen_function_wrapper(name, local_vars, args_dispatch)
+    code = line_directive + code + gen_function_wrapper(name, local_vars,
+                                                        args_dispatch)
     preprocessor_check_start, preprocessor_check_end = \
         gen_dependencies(dependencies)
     dispatch_code = gen_dispatch(name, suite_dependencies + dependencies)
diff --git a/tests/scripts/test_generate_test_code.py b/tests/scripts/test_generate_test_code.py
index 29d9e4f..149159c 100755
--- a/tests/scripts/test_generate_test_code.py
+++ b/tests/scripts/test_generate_test_code.py
@@ -31,7 +31,7 @@
 from generate_test_code import parse_until_pattern, GeneratorInputError
 from generate_test_code import parse_suite_dependencies
 from generate_test_code import parse_function_dependencies
-from generate_test_code import parse_function_signature, parse_function_code
+from generate_test_code import parse_function_arguments, parse_function_code
 from generate_test_code import parse_functions, END_HEADER_REGEX
 from generate_test_code import END_SUITE_HELPERS_REGEX, escaped_split
 from generate_test_code import parse_test_data, gen_dep_check
@@ -476,7 +476,7 @@
 
 class ParseFuncSignature(TestCase):
     """
-    Test Suite for parse_function_signature().
+    Test Suite for parse_function_arguments().
     """
 
     def test_int_and_char_params(self):
@@ -485,8 +485,7 @@
         :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')
+        args, local, arg_dispatch = parse_function_arguments(line)
         self.assertEqual(args, ['char*', 'int', 'int'])
         self.assertEqual(local, '')
         self.assertEqual(arg_dispatch, ['(char *) params[0]',
@@ -499,8 +498,7 @@
         :return:
         """
         line = 'void entropy_threshold( char * a, data_t * h, int result )'
-        name, args, local, arg_dispatch = parse_function_signature(line)
-        self.assertEqual(name, 'entropy_threshold')
+        args, local, arg_dispatch = parse_function_arguments(line)
         self.assertEqual(args, ['char*', 'hex', 'int'])
         self.assertEqual(local,
                          '    data_t data1 = {(uint8_t *) params[1], '
@@ -509,21 +507,13 @@
                                         '&data1',
                                         '*( (int *) params[3] )'])
 
-    def test_non_void_function(self):
-        """
-        Test invalid signature (non void).
-        :return:
-        """
-        line = 'int entropy_threshold( char * a, data_t * h, int result )'
-        self.assertRaises(ValueError, parse_function_signature, line)
-
     def test_unsupported_arg(self):
         """
         Test unsupported arguments (not among int, char * and data_t)
         :return:
         """
-        line = 'int entropy_threshold( char * a, data_t * h, int * result )'
-        self.assertRaises(ValueError, parse_function_signature, line)
+        line = 'void entropy_threshold( char * a, data_t * h, char result )'
+        self.assertRaises(ValueError, parse_function_arguments, line)
 
     def test_no_params(self):
         """
@@ -531,8 +521,7 @@
         :return:
         """
         line = 'void entropy_threshold()'
-        name, args, local, arg_dispatch = parse_function_signature(line)
-        self.assertEqual(name, 'entropy_threshold')
+        args, local, arg_dispatch = parse_function_arguments(line)
         self.assertEqual(args, [])
         self.assertEqual(local, '')
         self.assertEqual(arg_dispatch, [])
@@ -554,8 +543,9 @@
 function
 '''
         stream = StringIOWrapper('test_suite_ut.function', data)
-        self.assertRaises(GeneratorInputError, parse_function_code, stream, [],
-                          [])
+        err_msg = 'file: test_suite_ut.function - Test functions not found!'
+        self.assertRaisesRegexp(GeneratorInputError, err_msg,
+                                parse_function_code, stream, [], [])
 
     def test_no_end_case_comment(self):
         """
@@ -568,17 +558,19 @@
 }
 '''
         stream = StringIOWrapper('test_suite_ut.function', data)
-        self.assertRaises(GeneratorInputError, parse_function_code, stream, [],
-                          [])
+        err_msg = r'file: test_suite_ut.function - '\
+                  'end case pattern .*? not found!'
+        self.assertRaisesRegexp(GeneratorInputError, err_msg,
+                                parse_function_code, stream, [], [])
 
-    @patch("generate_test_code.parse_function_signature")
+    @patch("generate_test_code.parse_function_arguments")
     def test_function_called(self,
-                             parse_function_signature_mock):
+                             parse_function_arguments_mock):
         """
         Test parse_function_code()
         :return:
         """
-        parse_function_signature_mock.return_value = ('test_func', [], '', [])
+        parse_function_arguments_mock.return_value = ([], '', [])
         data = '''
 void test_func()
 {
@@ -587,14 +579,14 @@
         stream = StringIOWrapper('test_suite_ut.function', data)
         self.assertRaises(GeneratorInputError, parse_function_code,
                           stream, [], [])
-        self.assertTrue(parse_function_signature_mock.called)
-        parse_function_signature_mock.assert_called_with('void test_func()\n')
+        self.assertTrue(parse_function_arguments_mock.called)
+        parse_function_arguments_mock.assert_called_with('void test_func()\n')
 
     @patch("generate_test_code.gen_dispatch")
     @patch("generate_test_code.gen_dependencies")
     @patch("generate_test_code.gen_function_wrapper")
-    @patch("generate_test_code.parse_function_signature")
-    def test_return(self, parse_function_signature_mock,
+    @patch("generate_test_code.parse_function_arguments")
+    def test_return(self, parse_function_arguments_mock,
                     gen_function_wrapper_mock,
                     gen_dependencies_mock,
                     gen_dispatch_mock):
@@ -602,7 +594,7 @@
         Test generated code.
         :return:
         """
-        parse_function_signature_mock.return_value = ('func', [], '', [])
+        parse_function_arguments_mock.return_value = ([], '', [])
         gen_function_wrapper_mock.return_value = ''
         gen_dependencies_mock.side_effect = gen_dependencies
         gen_dispatch_mock.side_effect = gen_dispatch
@@ -617,8 +609,8 @@
         stream = StringIOWrapper('test_suite_ut.function', data)
         name, arg, code, dispatch_code = parse_function_code(stream, [], [])
 
-        self.assertTrue(parse_function_signature_mock.called)
-        parse_function_signature_mock.assert_called_with('void func()\n')
+        self.assertTrue(parse_function_arguments_mock.called)
+        parse_function_arguments_mock.assert_called_with('void func()\n')
         gen_function_wrapper_mock.assert_called_with('test_func', '', [])
         self.assertEqual(name, 'test_func')
         self.assertEqual(arg, [])
@@ -638,8 +630,8 @@
     @patch("generate_test_code.gen_dispatch")
     @patch("generate_test_code.gen_dependencies")
     @patch("generate_test_code.gen_function_wrapper")
-    @patch("generate_test_code.parse_function_signature")
-    def test_with_exit_label(self, parse_function_signature_mock,
+    @patch("generate_test_code.parse_function_arguments")
+    def test_with_exit_label(self, parse_function_arguments_mock,
                              gen_function_wrapper_mock,
                              gen_dependencies_mock,
                              gen_dispatch_mock):
@@ -647,7 +639,7 @@
         Test when exit label is present.
         :return:
         """
-        parse_function_signature_mock.return_value = ('func', [], '', [])
+        parse_function_arguments_mock.return_value = ([], '', [])
         gen_function_wrapper_mock.return_value = ''
         gen_dependencies_mock.side_effect = gen_dependencies
         gen_dispatch_mock.side_effect = gen_dispatch
@@ -678,6 +670,66 @@
 '''
         self.assertEqual(code, expected)
 
+    def test_non_void_function(self):
+        """
+        Test invalid signature (non void).
+        :return:
+        """
+        data = 'int entropy_threshold( char * a, data_t * h, int result )'
+        err_msg = 'file: test_suite_ut.function - Test functions not found!'
+        stream = StringIOWrapper('test_suite_ut.function', data)
+        self.assertRaisesRegexp(GeneratorInputError, err_msg,
+                                parse_function_code, stream, [], [])
+
+    @patch("generate_test_code.gen_dispatch")
+    @patch("generate_test_code.gen_dependencies")
+    @patch("generate_test_code.gen_function_wrapper")
+    @patch("generate_test_code.parse_function_arguments")
+    def test_functio_name_on_newline(self, parse_function_arguments_mock,
+                                     gen_function_wrapper_mock,
+                                     gen_dependencies_mock,
+                                     gen_dispatch_mock):
+        """
+        Test when exit label is present.
+        :return:
+        """
+        parse_function_arguments_mock.return_value = ([], '', [])
+        gen_function_wrapper_mock.return_value = ''
+        gen_dependencies_mock.side_effect = gen_dependencies
+        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 */
+'''
+        stream = StringIOWrapper('test_suite_ut.function', data)
+        _, _, code, _ = parse_function_code(stream, [], [])
+
+        expected = '''#line 1 "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):
     """