• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Unit test for generate_test_code.py
3#
4# Copyright The Mbed TLS Contributors
5# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6#
7# This file is provided under the Apache License 2.0, or the
8# GNU General Public License v2.0 or later.
9#
10# **********
11# Apache License 2.0:
12#
13# Licensed under the Apache License, Version 2.0 (the "License"); you may
14# not use this file except in compliance with the License.
15# You may obtain a copy of the License at
16#
17# http://www.apache.org/licenses/LICENSE-2.0
18#
19# Unless required by applicable law or agreed to in writing, software
20# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22# See the License for the specific language governing permissions and
23# limitations under the License.
24#
25# **********
26#
27# **********
28# GNU General Public License v2.0 or later:
29#
30# This program is free software; you can redistribute it and/or modify
31# it under the terms of the GNU General Public License as published by
32# the Free Software Foundation; either version 2 of the License, or
33# (at your option) any later version.
34#
35# This program is distributed in the hope that it will be useful,
36# but WITHOUT ANY WARRANTY; without even the implied warranty of
37# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38# GNU General Public License for more details.
39#
40# You should have received a copy of the GNU General Public License along
41# with this program; if not, write to the Free Software Foundation, Inc.,
42# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43#
44# **********
45
46"""
47Unit tests for generate_test_code.py
48"""
49
50# pylint: disable=wrong-import-order
51try:
52    # Python 2
53    from StringIO import StringIO
54except ImportError:
55    # Python 3
56    from io import StringIO
57from unittest import TestCase, main as unittest_main
58try:
59    # Python 2
60    from mock import patch
61except ImportError:
62    # Python 3
63    from unittest.mock import patch
64# pylint: enable=wrong-import-order
65from generate_test_code import gen_dependencies, gen_dependencies_one_line
66from generate_test_code import gen_function_wrapper, gen_dispatch
67from generate_test_code import parse_until_pattern, GeneratorInputError
68from generate_test_code import parse_suite_dependencies
69from generate_test_code import parse_function_dependencies
70from generate_test_code import parse_function_arguments, parse_function_code
71from generate_test_code import parse_functions, END_HEADER_REGEX
72from generate_test_code import END_SUITE_HELPERS_REGEX, escaped_split
73from generate_test_code import parse_test_data, gen_dep_check
74from generate_test_code import gen_expression_check, write_dependencies
75from generate_test_code import write_parameters, gen_suite_dep_checks
76from generate_test_code import gen_from_test_data
77
78
79class GenDep(TestCase):
80    """
81    Test suite for function gen_dep()
82    """
83
84    def test_dependencies_list(self):
85        """
86        Test that gen_dep() correctly creates dependencies for given
87        dependency list.
88        :return:
89        """
90        dependencies = ['DEP1', 'DEP2']
91        dep_start, dep_end = gen_dependencies(dependencies)
92        preprocessor1, preprocessor2 = dep_start.splitlines()
93        endif1, endif2 = dep_end.splitlines()
94        self.assertEqual(preprocessor1, '#if defined(DEP1)',
95                         'Preprocessor generated incorrectly')
96        self.assertEqual(preprocessor2, '#if defined(DEP2)',
97                         'Preprocessor generated incorrectly')
98        self.assertEqual(endif1, '#endif /* DEP2 */',
99                         'Preprocessor generated incorrectly')
100        self.assertEqual(endif2, '#endif /* DEP1 */',
101                         'Preprocessor generated incorrectly')
102
103    def test_disabled_dependencies_list(self):
104        """
105        Test that gen_dep() correctly creates dependencies for given
106        dependency list.
107        :return:
108        """
109        dependencies = ['!DEP1', '!DEP2']
110        dep_start, dep_end = gen_dependencies(dependencies)
111        preprocessor1, preprocessor2 = dep_start.splitlines()
112        endif1, endif2 = dep_end.splitlines()
113        self.assertEqual(preprocessor1, '#if !defined(DEP1)',
114                         'Preprocessor generated incorrectly')
115        self.assertEqual(preprocessor2, '#if !defined(DEP2)',
116                         'Preprocessor generated incorrectly')
117        self.assertEqual(endif1, '#endif /* !DEP2 */',
118                         'Preprocessor generated incorrectly')
119        self.assertEqual(endif2, '#endif /* !DEP1 */',
120                         'Preprocessor generated incorrectly')
121
122    def test_mixed_dependencies_list(self):
123        """
124        Test that gen_dep() correctly creates dependencies for given
125        dependency list.
126        :return:
127        """
128        dependencies = ['!DEP1', 'DEP2']
129        dep_start, dep_end = gen_dependencies(dependencies)
130        preprocessor1, preprocessor2 = dep_start.splitlines()
131        endif1, endif2 = dep_end.splitlines()
132        self.assertEqual(preprocessor1, '#if !defined(DEP1)',
133                         'Preprocessor generated incorrectly')
134        self.assertEqual(preprocessor2, '#if defined(DEP2)',
135                         'Preprocessor generated incorrectly')
136        self.assertEqual(endif1, '#endif /* DEP2 */',
137                         'Preprocessor generated incorrectly')
138        self.assertEqual(endif2, '#endif /* !DEP1 */',
139                         'Preprocessor generated incorrectly')
140
141    def test_empty_dependencies_list(self):
142        """
143        Test that gen_dep() correctly creates dependencies for given
144        dependency list.
145        :return:
146        """
147        dependencies = []
148        dep_start, dep_end = gen_dependencies(dependencies)
149        self.assertEqual(dep_start, '', 'Preprocessor generated incorrectly')
150        self.assertEqual(dep_end, '', 'Preprocessor generated incorrectly')
151
152    def test_large_dependencies_list(self):
153        """
154        Test that gen_dep() correctly creates dependencies for given
155        dependency list.
156        :return:
157        """
158        dependencies = []
159        count = 10
160        for i in range(count):
161            dependencies.append('DEP%d' % i)
162        dep_start, dep_end = gen_dependencies(dependencies)
163        self.assertEqual(len(dep_start.splitlines()), count,
164                         'Preprocessor generated incorrectly')
165        self.assertEqual(len(dep_end.splitlines()), count,
166                         'Preprocessor generated incorrectly')
167
168
169class GenDepOneLine(TestCase):
170    """
171    Test Suite for testing gen_dependencies_one_line()
172    """
173
174    def test_dependencies_list(self):
175        """
176        Test that gen_dep() correctly creates dependencies for given
177        dependency list.
178        :return:
179        """
180        dependencies = ['DEP1', 'DEP2']
181        dep_str = gen_dependencies_one_line(dependencies)
182        self.assertEqual(dep_str, '#if defined(DEP1) && defined(DEP2)',
183                         'Preprocessor generated incorrectly')
184
185    def test_disabled_dependencies_list(self):
186        """
187        Test that gen_dep() correctly creates dependencies for given
188        dependency list.
189        :return:
190        """
191        dependencies = ['!DEP1', '!DEP2']
192        dep_str = gen_dependencies_one_line(dependencies)
193        self.assertEqual(dep_str, '#if !defined(DEP1) && !defined(DEP2)',
194                         'Preprocessor generated incorrectly')
195
196    def test_mixed_dependencies_list(self):
197        """
198        Test that gen_dep() correctly creates dependencies for given
199        dependency list.
200        :return:
201        """
202        dependencies = ['!DEP1', 'DEP2']
203        dep_str = gen_dependencies_one_line(dependencies)
204        self.assertEqual(dep_str, '#if !defined(DEP1) && defined(DEP2)',
205                         'Preprocessor generated incorrectly')
206
207    def test_empty_dependencies_list(self):
208        """
209        Test that gen_dep() correctly creates dependencies for given
210        dependency list.
211        :return:
212        """
213        dependencies = []
214        dep_str = gen_dependencies_one_line(dependencies)
215        self.assertEqual(dep_str, '', 'Preprocessor generated incorrectly')
216
217    def test_large_dependencies_list(self):
218        """
219        Test that gen_dep() correctly creates dependencies for given
220        dependency list.
221        :return:
222        """
223        dependencies = []
224        count = 10
225        for i in range(count):
226            dependencies.append('DEP%d' % i)
227        dep_str = gen_dependencies_one_line(dependencies)
228        expected = '#if ' + ' && '.join(['defined(%s)' %
229                                         x for x in dependencies])
230        self.assertEqual(dep_str, expected,
231                         'Preprocessor generated incorrectly')
232
233
234class GenFunctionWrapper(TestCase):
235    """
236    Test Suite for testing gen_function_wrapper()
237    """
238
239    def test_params_unpack(self):
240        """
241        Test that params are properly unpacked in the function call.
242
243        :return:
244        """
245        code = gen_function_wrapper('test_a', '', ('a', 'b', 'c', 'd'))
246        expected = '''
247void test_a_wrapper( void ** params )
248{
249
250    test_a( a, b, c, d );
251}
252'''
253        self.assertEqual(code, expected)
254
255    def test_local(self):
256        """
257        Test that params are properly unpacked in the function call.
258
259        :return:
260        """
261        code = gen_function_wrapper('test_a',
262                                    'int x = 1;', ('x', 'b', 'c', 'd'))
263        expected = '''
264void test_a_wrapper( void ** params )
265{
266int x = 1;
267    test_a( x, b, c, d );
268}
269'''
270        self.assertEqual(code, expected)
271
272    def test_empty_params(self):
273        """
274        Test that params are properly unpacked in the function call.
275
276        :return:
277        """
278        code = gen_function_wrapper('test_a', '', ())
279        expected = '''
280void test_a_wrapper( void ** params )
281{
282    (void)params;
283
284    test_a(  );
285}
286'''
287        self.assertEqual(code, expected)
288
289
290class GenDispatch(TestCase):
291    """
292    Test suite for testing gen_dispatch()
293    """
294
295    def test_dispatch(self):
296        """
297        Test that dispatch table entry is generated correctly.
298        :return:
299        """
300        code = gen_dispatch('test_a', ['DEP1', 'DEP2'])
301        expected = '''
302#if defined(DEP1) && defined(DEP2)
303    test_a_wrapper,
304#else
305    NULL,
306#endif
307'''
308        self.assertEqual(code, expected)
309
310    def test_empty_dependencies(self):
311        """
312        Test empty dependency list.
313        :return:
314        """
315        code = gen_dispatch('test_a', [])
316        expected = '''
317    test_a_wrapper,
318'''
319        self.assertEqual(code, expected)
320
321
322class StringIOWrapper(StringIO):
323    """
324    file like class to mock file object in tests.
325    """
326    def __init__(self, file_name, data, line_no=0):
327        """
328        Init file handle.
329
330        :param file_name:
331        :param data:
332        :param line_no:
333        """
334        super(StringIOWrapper, self).__init__(data)
335        self.line_no = line_no
336        self.name = file_name
337
338    def next(self):
339        """
340        Iterator method. This method overrides base class's
341        next method and extends the next method to count the line
342        numbers as each line is read.
343
344        :return: Line read from file.
345        """
346        parent = super(StringIOWrapper, self)
347        if getattr(parent, 'next', None):
348            # Python 2
349            line = parent.next()
350        else:
351            # Python 3
352            line = parent.__next__()
353        return line
354
355    # Python 3
356    __next__ = next
357
358    def readline(self, length=0):
359        """
360        Wrap the base class readline.
361
362        :param length:
363        :return:
364        """
365        # pylint: disable=unused-argument
366        line = super(StringIOWrapper, self).readline()
367        if line is not None:
368            self.line_no += 1
369        return line
370
371
372class ParseUntilPattern(TestCase):
373    """
374    Test Suite for testing parse_until_pattern().
375    """
376
377    def test_suite_headers(self):
378        """
379        Test that suite headers are parsed correctly.
380
381        :return:
382        """
383        data = '''#include "mbedtls/ecp.h"
384
385#define ECP_PF_UNKNOWN     -1
386/* END_HEADER */
387'''
388        expected = '''#line 1 "test_suite_ut.function"
389#include "mbedtls/ecp.h"
390
391#define ECP_PF_UNKNOWN     -1
392'''
393        stream = StringIOWrapper('test_suite_ut.function', data, line_no=0)
394        headers = parse_until_pattern(stream, END_HEADER_REGEX)
395        self.assertEqual(headers, expected)
396
397    def test_line_no(self):
398        """
399        Test that #line is set to correct line no. in source .function file.
400
401        :return:
402        """
403        data = '''#include "mbedtls/ecp.h"
404
405#define ECP_PF_UNKNOWN     -1
406/* END_HEADER */
407'''
408        offset_line_no = 5
409        expected = '''#line %d "test_suite_ut.function"
410#include "mbedtls/ecp.h"
411
412#define ECP_PF_UNKNOWN     -1
413''' % (offset_line_no + 1)
414        stream = StringIOWrapper('test_suite_ut.function', data,
415                                 offset_line_no)
416        headers = parse_until_pattern(stream, END_HEADER_REGEX)
417        self.assertEqual(headers, expected)
418
419    def test_no_end_header_comment(self):
420        """
421        Test that InvalidFileFormat is raised when end header comment is
422        missing.
423        :return:
424        """
425        data = '''#include "mbedtls/ecp.h"
426
427#define ECP_PF_UNKNOWN     -1
428
429'''
430        stream = StringIOWrapper('test_suite_ut.function', data)
431        self.assertRaises(GeneratorInputError, parse_until_pattern, stream,
432                          END_HEADER_REGEX)
433
434
435class ParseSuiteDependencies(TestCase):
436    """
437    Test Suite for testing parse_suite_dependencies().
438    """
439
440    def test_suite_dependencies(self):
441        """
442
443        :return:
444        """
445        data = '''
446 * depends_on:MBEDTLS_ECP_C
447 * END_DEPENDENCIES
448 */
449'''
450        expected = ['MBEDTLS_ECP_C']
451        stream = StringIOWrapper('test_suite_ut.function', data)
452        dependencies = parse_suite_dependencies(stream)
453        self.assertEqual(dependencies, expected)
454
455    def test_no_end_dep_comment(self):
456        """
457        Test that InvalidFileFormat is raised when end dep comment is missing.
458        :return:
459        """
460        data = '''
461* depends_on:MBEDTLS_ECP_C
462'''
463        stream = StringIOWrapper('test_suite_ut.function', data)
464        self.assertRaises(GeneratorInputError, parse_suite_dependencies,
465                          stream)
466
467    def test_dependencies_split(self):
468        """
469        Test that InvalidFileFormat is raised when end dep comment is missing.
470        :return:
471        """
472        data = '''
473 * depends_on:MBEDTLS_ECP_C:A:B:   C  : D :F : G: !H
474 * END_DEPENDENCIES
475 */
476'''
477        expected = ['MBEDTLS_ECP_C', 'A', 'B', 'C', 'D', 'F', 'G', '!H']
478        stream = StringIOWrapper('test_suite_ut.function', data)
479        dependencies = parse_suite_dependencies(stream)
480        self.assertEqual(dependencies, expected)
481
482
483class ParseFuncDependencies(TestCase):
484    """
485    Test Suite for testing parse_function_dependencies()
486    """
487
488    def test_function_dependencies(self):
489        """
490        Test that parse_function_dependencies() correctly parses function
491        dependencies.
492        :return:
493        """
494        line = '/* BEGIN_CASE ' \
495               'depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */'
496        expected = ['MBEDTLS_ENTROPY_NV_SEED', 'MBEDTLS_FS_IO']
497        dependencies = parse_function_dependencies(line)
498        self.assertEqual(dependencies, expected)
499
500    def test_no_dependencies(self):
501        """
502        Test that parse_function_dependencies() correctly parses function
503        dependencies.
504        :return:
505        """
506        line = '/* BEGIN_CASE */'
507        dependencies = parse_function_dependencies(line)
508        self.assertEqual(dependencies, [])
509
510    def test_tolerance(self):
511        """
512        Test that parse_function_dependencies() correctly parses function
513        dependencies.
514        :return:
515        """
516        line = '/* BEGIN_CASE depends_on:MBEDTLS_FS_IO: A : !B:C : F*/'
517        dependencies = parse_function_dependencies(line)
518        self.assertEqual(dependencies, ['MBEDTLS_FS_IO', 'A', '!B', 'C', 'F'])
519
520
521class ParseFuncSignature(TestCase):
522    """
523    Test Suite for parse_function_arguments().
524    """
525
526    def test_int_and_char_params(self):
527        """
528        Test int and char parameters parsing
529        :return:
530        """
531        line = 'void entropy_threshold( char * a, int b, int result )'
532        args, local, arg_dispatch = parse_function_arguments(line)
533        self.assertEqual(args, ['char*', 'int', 'int'])
534        self.assertEqual(local, '')
535        self.assertEqual(arg_dispatch, ['(char *) params[0]',
536                                        '*( (int *) params[1] )',
537                                        '*( (int *) params[2] )'])
538
539    def test_hex_params(self):
540        """
541        Test hex parameters parsing
542        :return:
543        """
544        line = 'void entropy_threshold( char * a, data_t * h, int result )'
545        args, local, arg_dispatch = parse_function_arguments(line)
546        self.assertEqual(args, ['char*', 'hex', 'int'])
547        self.assertEqual(local,
548                         '    data_t data1 = {(uint8_t *) params[1], '
549                         '*( (uint32_t *) params[2] )};\n')
550        self.assertEqual(arg_dispatch, ['(char *) params[0]',
551                                        '&data1',
552                                        '*( (int *) params[3] )'])
553
554    def test_unsupported_arg(self):
555        """
556        Test unsupported arguments (not among int, char * and data_t)
557        :return:
558        """
559        line = 'void entropy_threshold( char * a, data_t * h, char result )'
560        self.assertRaises(ValueError, parse_function_arguments, line)
561
562    def test_no_params(self):
563        """
564        Test no parameters.
565        :return:
566        """
567        line = 'void entropy_threshold()'
568        args, local, arg_dispatch = parse_function_arguments(line)
569        self.assertEqual(args, [])
570        self.assertEqual(local, '')
571        self.assertEqual(arg_dispatch, [])
572
573
574class ParseFunctionCode(TestCase):
575    """
576    Test suite for testing parse_function_code()
577    """
578
579    def assert_raises_regex(self, exp, regex, func, *args):
580        """
581        Python 2 & 3 portable wrapper of assertRaisesRegex(p)? function.
582
583        :param exp: Exception type expected to be raised by cb.
584        :param regex: Expected exception message
585        :param func: callable object under test
586        :param args: variable positional arguments
587        """
588        parent = super(ParseFunctionCode, self)
589
590        # Pylint does not appreciate that the super method called
591        # conditionally can be available in other Python version
592        # then that of Pylint.
593        # Workaround is to call the method via getattr.
594        # Pylint ignores that the method got via getattr is
595        # conditionally executed. Method has to be a callable.
596        # Hence, using a dummy callable for getattr default.
597        dummy = lambda *x: None
598        # First Python 3 assertRaisesRegex is checked, since Python 2
599        # assertRaisesRegexp is also available in Python 3 but is
600        # marked deprecated.
601        for name in ('assertRaisesRegex', 'assertRaisesRegexp'):
602            method = getattr(parent, name, dummy)
603            if method is not dummy:
604                method(exp, regex, func, *args)
605                break
606        else:
607            raise AttributeError(" 'ParseFunctionCode' object has no attribute"
608                                 " 'assertRaisesRegex' or 'assertRaisesRegexp'"
609                                )
610
611    def test_no_function(self):
612        """
613        Test no test function found.
614        :return:
615        """
616        data = '''
617No
618test
619function
620'''
621        stream = StringIOWrapper('test_suite_ut.function', data)
622        err_msg = 'file: test_suite_ut.function - Test functions not found!'
623        self.assert_raises_regex(GeneratorInputError, err_msg,
624                                 parse_function_code, stream, [], [])
625
626    def test_no_end_case_comment(self):
627        """
628        Test missing end case.
629        :return:
630        """
631        data = '''
632void test_func()
633{
634}
635'''
636        stream = StringIOWrapper('test_suite_ut.function', data)
637        err_msg = r'file: test_suite_ut.function - '\
638                  'end case pattern .*? not found!'
639        self.assert_raises_regex(GeneratorInputError, err_msg,
640                                 parse_function_code, stream, [], [])
641
642    @patch("generate_test_code.parse_function_arguments")
643    def test_function_called(self,
644                             parse_function_arguments_mock):
645        """
646        Test parse_function_code()
647        :return:
648        """
649        parse_function_arguments_mock.return_value = ([], '', [])
650        data = '''
651void test_func()
652{
653}
654'''
655        stream = StringIOWrapper('test_suite_ut.function', data)
656        self.assertRaises(GeneratorInputError, parse_function_code,
657                          stream, [], [])
658        self.assertTrue(parse_function_arguments_mock.called)
659        parse_function_arguments_mock.assert_called_with('void test_func()\n')
660
661    @patch("generate_test_code.gen_dispatch")
662    @patch("generate_test_code.gen_dependencies")
663    @patch("generate_test_code.gen_function_wrapper")
664    @patch("generate_test_code.parse_function_arguments")
665    def test_return(self, parse_function_arguments_mock,
666                    gen_function_wrapper_mock,
667                    gen_dependencies_mock,
668                    gen_dispatch_mock):
669        """
670        Test generated code.
671        :return:
672        """
673        parse_function_arguments_mock.return_value = ([], '', [])
674        gen_function_wrapper_mock.return_value = ''
675        gen_dependencies_mock.side_effect = gen_dependencies
676        gen_dispatch_mock.side_effect = gen_dispatch
677        data = '''
678void func()
679{
680    ba ba black sheep
681    have you any wool
682}
683/* END_CASE */
684'''
685        stream = StringIOWrapper('test_suite_ut.function', data)
686        name, arg, code, dispatch_code = parse_function_code(stream, [], [])
687
688        self.assertTrue(parse_function_arguments_mock.called)
689        parse_function_arguments_mock.assert_called_with('void func()\n')
690        gen_function_wrapper_mock.assert_called_with('test_func', '', [])
691        self.assertEqual(name, 'test_func')
692        self.assertEqual(arg, [])
693        expected = '''#line 1 "test_suite_ut.function"
694
695void test_func()
696{
697    ba ba black sheep
698    have you any wool
699exit:
700    ;
701}
702'''
703        self.assertEqual(code, expected)
704        self.assertEqual(dispatch_code, "\n    test_func_wrapper,\n")
705
706    @patch("generate_test_code.gen_dispatch")
707    @patch("generate_test_code.gen_dependencies")
708    @patch("generate_test_code.gen_function_wrapper")
709    @patch("generate_test_code.parse_function_arguments")
710    def test_with_exit_label(self, parse_function_arguments_mock,
711                             gen_function_wrapper_mock,
712                             gen_dependencies_mock,
713                             gen_dispatch_mock):
714        """
715        Test when exit label is present.
716        :return:
717        """
718        parse_function_arguments_mock.return_value = ([], '', [])
719        gen_function_wrapper_mock.return_value = ''
720        gen_dependencies_mock.side_effect = gen_dependencies
721        gen_dispatch_mock.side_effect = gen_dispatch
722        data = '''
723void func()
724{
725    ba ba black sheep
726    have you any wool
727exit:
728    yes sir yes sir
729    3 bags full
730}
731/* END_CASE */
732'''
733        stream = StringIOWrapper('test_suite_ut.function', data)
734        _, _, code, _ = parse_function_code(stream, [], [])
735
736        expected = '''#line 1 "test_suite_ut.function"
737
738void test_func()
739{
740    ba ba black sheep
741    have you any wool
742exit:
743    yes sir yes sir
744    3 bags full
745}
746'''
747        self.assertEqual(code, expected)
748
749    def test_non_void_function(self):
750        """
751        Test invalid signature (non void).
752        :return:
753        """
754        data = 'int entropy_threshold( char * a, data_t * h, int result )'
755        err_msg = 'file: test_suite_ut.function - Test functions not found!'
756        stream = StringIOWrapper('test_suite_ut.function', data)
757        self.assert_raises_regex(GeneratorInputError, err_msg,
758                                 parse_function_code, stream, [], [])
759
760    @patch("generate_test_code.gen_dispatch")
761    @patch("generate_test_code.gen_dependencies")
762    @patch("generate_test_code.gen_function_wrapper")
763    @patch("generate_test_code.parse_function_arguments")
764    def test_functio_name_on_newline(self, parse_function_arguments_mock,
765                                     gen_function_wrapper_mock,
766                                     gen_dependencies_mock,
767                                     gen_dispatch_mock):
768        """
769        Test when exit label is present.
770        :return:
771        """
772        parse_function_arguments_mock.return_value = ([], '', [])
773        gen_function_wrapper_mock.return_value = ''
774        gen_dependencies_mock.side_effect = gen_dependencies
775        gen_dispatch_mock.side_effect = gen_dispatch
776        data = '''
777void
778
779
780func()
781{
782    ba ba black sheep
783    have you any wool
784exit:
785    yes sir yes sir
786    3 bags full
787}
788/* END_CASE */
789'''
790        stream = StringIOWrapper('test_suite_ut.function', data)
791        _, _, code, _ = parse_function_code(stream, [], [])
792
793        expected = '''#line 1 "test_suite_ut.function"
794
795void
796
797
798test_func()
799{
800    ba ba black sheep
801    have you any wool
802exit:
803    yes sir yes sir
804    3 bags full
805}
806'''
807        self.assertEqual(code, expected)
808
809
810class ParseFunction(TestCase):
811    """
812    Test Suite for testing parse_functions()
813    """
814
815    @patch("generate_test_code.parse_until_pattern")
816    def test_begin_header(self, parse_until_pattern_mock):
817        """
818        Test that begin header is checked and parse_until_pattern() is called.
819        :return:
820        """
821        def stop(*_unused):
822            """Stop when parse_until_pattern is called."""
823            raise Exception
824        parse_until_pattern_mock.side_effect = stop
825        data = '''/* BEGIN_HEADER */
826#include "mbedtls/ecp.h"
827
828#define ECP_PF_UNKNOWN     -1
829/* END_HEADER */
830'''
831        stream = StringIOWrapper('test_suite_ut.function', data)
832        self.assertRaises(Exception, parse_functions, stream)
833        parse_until_pattern_mock.assert_called_with(stream, END_HEADER_REGEX)
834        self.assertEqual(stream.line_no, 1)
835
836    @patch("generate_test_code.parse_until_pattern")
837    def test_begin_helper(self, parse_until_pattern_mock):
838        """
839        Test that begin helper is checked and parse_until_pattern() is called.
840        :return:
841        """
842        def stop(*_unused):
843            """Stop when parse_until_pattern is called."""
844            raise Exception
845        parse_until_pattern_mock.side_effect = stop
846        data = '''/* BEGIN_SUITE_HELPERS */
847void print_hello_world()
848{
849    printf("Hello World!\n");
850}
851/* END_SUITE_HELPERS */
852'''
853        stream = StringIOWrapper('test_suite_ut.function', data)
854        self.assertRaises(Exception, parse_functions, stream)
855        parse_until_pattern_mock.assert_called_with(stream,
856                                                    END_SUITE_HELPERS_REGEX)
857        self.assertEqual(stream.line_no, 1)
858
859    @patch("generate_test_code.parse_suite_dependencies")
860    def test_begin_dep(self, parse_suite_dependencies_mock):
861        """
862        Test that begin dep is checked and parse_suite_dependencies() is
863        called.
864        :return:
865        """
866        def stop(*_unused):
867            """Stop when parse_until_pattern is called."""
868            raise Exception
869        parse_suite_dependencies_mock.side_effect = stop
870        data = '''/* BEGIN_DEPENDENCIES
871 * depends_on:MBEDTLS_ECP_C
872 * END_DEPENDENCIES
873 */
874'''
875        stream = StringIOWrapper('test_suite_ut.function', data)
876        self.assertRaises(Exception, parse_functions, stream)
877        parse_suite_dependencies_mock.assert_called_with(stream)
878        self.assertEqual(stream.line_no, 1)
879
880    @patch("generate_test_code.parse_function_dependencies")
881    def test_begin_function_dep(self, func_mock):
882        """
883        Test that begin dep is checked and parse_function_dependencies() is
884        called.
885        :return:
886        """
887        def stop(*_unused):
888            """Stop when parse_until_pattern is called."""
889            raise Exception
890        func_mock.side_effect = stop
891
892        dependencies_str = '/* BEGIN_CASE ' \
893            'depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */\n'
894        data = '''%svoid test_func()
895{
896}
897''' % dependencies_str
898        stream = StringIOWrapper('test_suite_ut.function', data)
899        self.assertRaises(Exception, parse_functions, stream)
900        func_mock.assert_called_with(dependencies_str)
901        self.assertEqual(stream.line_no, 1)
902
903    @patch("generate_test_code.parse_function_code")
904    @patch("generate_test_code.parse_function_dependencies")
905    def test_return(self, func_mock1, func_mock2):
906        """
907        Test that begin case is checked and parse_function_code() is called.
908        :return:
909        """
910        func_mock1.return_value = []
911        in_func_code = '''void test_func()
912{
913}
914'''
915        func_dispatch = '''
916    test_func_wrapper,
917'''
918        func_mock2.return_value = 'test_func', [],\
919            in_func_code, func_dispatch
920        dependencies_str = '/* BEGIN_CASE ' \
921            'depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */\n'
922        data = '''%svoid test_func()
923{
924}
925''' % dependencies_str
926        stream = StringIOWrapper('test_suite_ut.function', data)
927        suite_dependencies, dispatch_code, func_code, func_info = \
928            parse_functions(stream)
929        func_mock1.assert_called_with(dependencies_str)
930        func_mock2.assert_called_with(stream, [], [])
931        self.assertEqual(stream.line_no, 5)
932        self.assertEqual(suite_dependencies, [])
933        expected_dispatch_code = '''/* Function Id: 0 */
934
935    test_func_wrapper,
936'''
937        self.assertEqual(dispatch_code, expected_dispatch_code)
938        self.assertEqual(func_code, in_func_code)
939        self.assertEqual(func_info, {'test_func': (0, [])})
940
941    def test_parsing(self):
942        """
943        Test case parsing.
944        :return:
945        """
946        data = '''/* BEGIN_HEADER */
947#include "mbedtls/ecp.h"
948
949#define ECP_PF_UNKNOWN     -1
950/* END_HEADER */
951
952/* BEGIN_DEPENDENCIES
953 * depends_on:MBEDTLS_ECP_C
954 * END_DEPENDENCIES
955 */
956
957/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
958void func1()
959{
960}
961/* END_CASE */
962
963/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
964void func2()
965{
966}
967/* END_CASE */
968'''
969        stream = StringIOWrapper('test_suite_ut.function', data)
970        suite_dependencies, dispatch_code, func_code, func_info = \
971            parse_functions(stream)
972        self.assertEqual(stream.line_no, 23)
973        self.assertEqual(suite_dependencies, ['MBEDTLS_ECP_C'])
974
975        expected_dispatch_code = '''/* Function Id: 0 */
976
977#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_ENTROPY_NV_SEED) && defined(MBEDTLS_FS_IO)
978    test_func1_wrapper,
979#else
980    NULL,
981#endif
982/* Function Id: 1 */
983
984#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_ENTROPY_NV_SEED) && defined(MBEDTLS_FS_IO)
985    test_func2_wrapper,
986#else
987    NULL,
988#endif
989'''
990        self.assertEqual(dispatch_code, expected_dispatch_code)
991        expected_func_code = '''#if defined(MBEDTLS_ECP_C)
992#line 2 "test_suite_ut.function"
993#include "mbedtls/ecp.h"
994
995#define ECP_PF_UNKNOWN     -1
996#if defined(MBEDTLS_ENTROPY_NV_SEED)
997#if defined(MBEDTLS_FS_IO)
998#line 13 "test_suite_ut.function"
999void test_func1()
1000{
1001exit:
1002    ;
1003}
1004
1005void test_func1_wrapper( void ** params )
1006{
1007    (void)params;
1008
1009    test_func1(  );
1010}
1011#endif /* MBEDTLS_FS_IO */
1012#endif /* MBEDTLS_ENTROPY_NV_SEED */
1013#if defined(MBEDTLS_ENTROPY_NV_SEED)
1014#if defined(MBEDTLS_FS_IO)
1015#line 19 "test_suite_ut.function"
1016void test_func2()
1017{
1018exit:
1019    ;
1020}
1021
1022void test_func2_wrapper( void ** params )
1023{
1024    (void)params;
1025
1026    test_func2(  );
1027}
1028#endif /* MBEDTLS_FS_IO */
1029#endif /* MBEDTLS_ENTROPY_NV_SEED */
1030#endif /* MBEDTLS_ECP_C */
1031'''
1032        self.assertEqual(func_code, expected_func_code)
1033        self.assertEqual(func_info, {'test_func1': (0, []),
1034                                     'test_func2': (1, [])})
1035
1036    def test_same_function_name(self):
1037        """
1038        Test name conflict.
1039        :return:
1040        """
1041        data = '''/* BEGIN_HEADER */
1042#include "mbedtls/ecp.h"
1043
1044#define ECP_PF_UNKNOWN     -1
1045/* END_HEADER */
1046
1047/* BEGIN_DEPENDENCIES
1048 * depends_on:MBEDTLS_ECP_C
1049 * END_DEPENDENCIES
1050 */
1051
1052/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
1053void func()
1054{
1055}
1056/* END_CASE */
1057
1058/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
1059void func()
1060{
1061}
1062/* END_CASE */
1063'''
1064        stream = StringIOWrapper('test_suite_ut.function', data)
1065        self.assertRaises(GeneratorInputError, parse_functions, stream)
1066
1067
1068class EscapedSplit(TestCase):
1069    """
1070    Test suite for testing escaped_split().
1071    Note: Since escaped_split() output is used to write back to the
1072    intermediate data file. Any escape characters in the input are
1073    retained in the output.
1074    """
1075
1076    def test_invalid_input(self):
1077        """
1078        Test when input split character is not a character.
1079        :return:
1080        """
1081        self.assertRaises(ValueError, escaped_split, '', 'string')
1082
1083    def test_empty_string(self):
1084        """
1085        Test empty string input.
1086        :return:
1087        """
1088        splits = escaped_split('', ':')
1089        self.assertEqual(splits, [])
1090
1091    def test_no_escape(self):
1092        """
1093        Test with no escape character. The behaviour should be same as
1094        str.split()
1095        :return:
1096        """
1097        test_str = 'yahoo:google'
1098        splits = escaped_split(test_str, ':')
1099        self.assertEqual(splits, test_str.split(':'))
1100
1101    def test_escaped_input(self):
1102        """
1103        Test input that has escaped delimiter.
1104        :return:
1105        """
1106        test_str = r'yahoo\:google:facebook'
1107        splits = escaped_split(test_str, ':')
1108        self.assertEqual(splits, [r'yahoo\:google', 'facebook'])
1109
1110    def test_escaped_escape(self):
1111        """
1112        Test input that has escaped delimiter.
1113        :return:
1114        """
1115        test_str = r'yahoo\\:google:facebook'
1116        splits = escaped_split(test_str, ':')
1117        self.assertEqual(splits, [r'yahoo\\', 'google', 'facebook'])
1118
1119    def test_all_at_once(self):
1120        """
1121        Test input that has escaped delimiter.
1122        :return:
1123        """
1124        test_str = r'yahoo\\:google:facebook\:instagram\\:bbc\\:wikipedia'
1125        splits = escaped_split(test_str, ':')
1126        self.assertEqual(splits, [r'yahoo\\', r'google',
1127                                  r'facebook\:instagram\\',
1128                                  r'bbc\\', r'wikipedia'])
1129
1130
1131class ParseTestData(TestCase):
1132    """
1133    Test suite for parse test data.
1134    """
1135
1136    def test_parser(self):
1137        """
1138        Test that tests are parsed correctly from data file.
1139        :return:
1140        """
1141        data = """
1142Diffie-Hellman full exchange #1
1143dhm_do_dhm:10:"23":10:"5"
1144
1145Diffie-Hellman full exchange #2
1146dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622"
1147
1148Diffie-Hellman full exchange #3
1149dhm_do_dhm:10:"9345098382739712938719287391879381271":10:"9345098792137312973297123912791271"
1150
1151Diffie-Hellman selftest
1152dhm_selftest:
1153"""
1154        stream = StringIOWrapper('test_suite_ut.function', data)
1155        # List of (name, function_name, dependencies, args)
1156        tests = list(parse_test_data(stream))
1157        test1, test2, test3, test4 = tests
1158        self.assertEqual(test1[0], 'Diffie-Hellman full exchange #1')
1159        self.assertEqual(test1[1], 'dhm_do_dhm')
1160        self.assertEqual(test1[2], [])
1161        self.assertEqual(test1[3], ['10', '"23"', '10', '"5"'])
1162
1163        self.assertEqual(test2[0], 'Diffie-Hellman full exchange #2')
1164        self.assertEqual(test2[1], 'dhm_do_dhm')
1165        self.assertEqual(test2[2], [])
1166        self.assertEqual(test2[3], ['10', '"93450983094850938450983409623"',
1167                                    '10', '"9345098304850938450983409622"'])
1168
1169        self.assertEqual(test3[0], 'Diffie-Hellman full exchange #3')
1170        self.assertEqual(test3[1], 'dhm_do_dhm')
1171        self.assertEqual(test3[2], [])
1172        self.assertEqual(test3[3], ['10',
1173                                    '"9345098382739712938719287391879381271"',
1174                                    '10',
1175                                    '"9345098792137312973297123912791271"'])
1176
1177        self.assertEqual(test4[0], 'Diffie-Hellman selftest')
1178        self.assertEqual(test4[1], 'dhm_selftest')
1179        self.assertEqual(test4[2], [])
1180        self.assertEqual(test4[3], [])
1181
1182    def test_with_dependencies(self):
1183        """
1184        Test that tests with dependencies are parsed.
1185        :return:
1186        """
1187        data = """
1188Diffie-Hellman full exchange #1
1189depends_on:YAHOO
1190dhm_do_dhm:10:"23":10:"5"
1191
1192Diffie-Hellman full exchange #2
1193dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622"
1194
1195"""
1196        stream = StringIOWrapper('test_suite_ut.function', data)
1197        # List of (name, function_name, dependencies, args)
1198        tests = list(parse_test_data(stream))
1199        test1, test2 = tests
1200        self.assertEqual(test1[0], 'Diffie-Hellman full exchange #1')
1201        self.assertEqual(test1[1], 'dhm_do_dhm')
1202        self.assertEqual(test1[2], ['YAHOO'])
1203        self.assertEqual(test1[3], ['10', '"23"', '10', '"5"'])
1204
1205        self.assertEqual(test2[0], 'Diffie-Hellman full exchange #2')
1206        self.assertEqual(test2[1], 'dhm_do_dhm')
1207        self.assertEqual(test2[2], [])
1208        self.assertEqual(test2[3], ['10', '"93450983094850938450983409623"',
1209                                    '10', '"9345098304850938450983409622"'])
1210
1211    def test_no_args(self):
1212        """
1213        Test GeneratorInputError is raised when test function name and
1214        args line is missing.
1215        :return:
1216        """
1217        data = """
1218Diffie-Hellman full exchange #1
1219depends_on:YAHOO
1220
1221
1222Diffie-Hellman full exchange #2
1223dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622"
1224
1225"""
1226        stream = StringIOWrapper('test_suite_ut.function', data)
1227        err = None
1228        try:
1229            for _, _, _, _ in parse_test_data(stream):
1230                pass
1231        except GeneratorInputError as err:
1232            self.assertEqual(type(err), GeneratorInputError)
1233
1234    def test_incomplete_data(self):
1235        """
1236        Test GeneratorInputError is raised when test function name
1237        and args line is missing.
1238        :return:
1239        """
1240        data = """
1241Diffie-Hellman full exchange #1
1242depends_on:YAHOO
1243"""
1244        stream = StringIOWrapper('test_suite_ut.function', data)
1245        err = None
1246        try:
1247            for _, _, _, _ in parse_test_data(stream):
1248                pass
1249        except GeneratorInputError as err:
1250            self.assertEqual(type(err), GeneratorInputError)
1251
1252
1253class GenDepCheck(TestCase):
1254    """
1255    Test suite for gen_dep_check(). It is assumed this function is
1256    called with valid inputs.
1257    """
1258
1259    def test_gen_dep_check(self):
1260        """
1261        Test that dependency check code generated correctly.
1262        :return:
1263        """
1264        expected = """
1265        case 5:
1266            {
1267#if defined(YAHOO)
1268                ret = DEPENDENCY_SUPPORTED;
1269#else
1270                ret = DEPENDENCY_NOT_SUPPORTED;
1271#endif
1272            }
1273            break;"""
1274        out = gen_dep_check(5, 'YAHOO')
1275        self.assertEqual(out, expected)
1276
1277    def test_not_defined_dependency(self):
1278        """
1279        Test dependency with !.
1280        :return:
1281        """
1282        expected = """
1283        case 5:
1284            {
1285#if !defined(YAHOO)
1286                ret = DEPENDENCY_SUPPORTED;
1287#else
1288                ret = DEPENDENCY_NOT_SUPPORTED;
1289#endif
1290            }
1291            break;"""
1292        out = gen_dep_check(5, '!YAHOO')
1293        self.assertEqual(out, expected)
1294
1295    def test_empty_dependency(self):
1296        """
1297        Test invalid dependency input.
1298        :return:
1299        """
1300        self.assertRaises(GeneratorInputError, gen_dep_check, 5, '!')
1301
1302    def test_negative_dep_id(self):
1303        """
1304        Test invalid dependency input.
1305        :return:
1306        """
1307        self.assertRaises(GeneratorInputError, gen_dep_check, -1, 'YAHOO')
1308
1309
1310class GenExpCheck(TestCase):
1311    """
1312    Test suite for gen_expression_check(). It is assumed this function
1313    is called with valid inputs.
1314    """
1315
1316    def test_gen_exp_check(self):
1317        """
1318        Test that expression check code generated correctly.
1319        :return:
1320        """
1321        expected = """
1322        case 5:
1323            {
1324                *out_value = YAHOO;
1325            }
1326            break;"""
1327        out = gen_expression_check(5, 'YAHOO')
1328        self.assertEqual(out, expected)
1329
1330    def test_invalid_expression(self):
1331        """
1332        Test invalid expression input.
1333        :return:
1334        """
1335        self.assertRaises(GeneratorInputError, gen_expression_check, 5, '')
1336
1337    def test_negative_exp_id(self):
1338        """
1339        Test invalid expression id.
1340        :return:
1341        """
1342        self.assertRaises(GeneratorInputError, gen_expression_check,
1343                          -1, 'YAHOO')
1344
1345
1346class WriteDependencies(TestCase):
1347    """
1348    Test suite for testing write_dependencies.
1349    """
1350
1351    def test_no_test_dependencies(self):
1352        """
1353        Test when test dependencies input is empty.
1354        :return:
1355        """
1356        stream = StringIOWrapper('test_suite_ut.data', '')
1357        unique_dependencies = []
1358        dep_check_code = write_dependencies(stream, [], unique_dependencies)
1359        self.assertEqual(dep_check_code, '')
1360        self.assertEqual(len(unique_dependencies), 0)
1361        self.assertEqual(stream.getvalue(), '')
1362
1363    def test_unique_dep_ids(self):
1364        """
1365
1366        :return:
1367        """
1368        stream = StringIOWrapper('test_suite_ut.data', '')
1369        unique_dependencies = []
1370        dep_check_code = write_dependencies(stream, ['DEP3', 'DEP2', 'DEP1'],
1371                                            unique_dependencies)
1372        expect_dep_check_code = '''
1373        case 0:
1374            {
1375#if defined(DEP3)
1376                ret = DEPENDENCY_SUPPORTED;
1377#else
1378                ret = DEPENDENCY_NOT_SUPPORTED;
1379#endif
1380            }
1381            break;
1382        case 1:
1383            {
1384#if defined(DEP2)
1385                ret = DEPENDENCY_SUPPORTED;
1386#else
1387                ret = DEPENDENCY_NOT_SUPPORTED;
1388#endif
1389            }
1390            break;
1391        case 2:
1392            {
1393#if defined(DEP1)
1394                ret = DEPENDENCY_SUPPORTED;
1395#else
1396                ret = DEPENDENCY_NOT_SUPPORTED;
1397#endif
1398            }
1399            break;'''
1400        self.assertEqual(dep_check_code, expect_dep_check_code)
1401        self.assertEqual(len(unique_dependencies), 3)
1402        self.assertEqual(stream.getvalue(), 'depends_on:0:1:2\n')
1403
1404    def test_dep_id_repeat(self):
1405        """
1406
1407        :return:
1408        """
1409        stream = StringIOWrapper('test_suite_ut.data', '')
1410        unique_dependencies = []
1411        dep_check_code = ''
1412        dep_check_code += write_dependencies(stream, ['DEP3', 'DEP2'],
1413                                             unique_dependencies)
1414        dep_check_code += write_dependencies(stream, ['DEP2', 'DEP1'],
1415                                             unique_dependencies)
1416        dep_check_code += write_dependencies(stream, ['DEP1', 'DEP3'],
1417                                             unique_dependencies)
1418        expect_dep_check_code = '''
1419        case 0:
1420            {
1421#if defined(DEP3)
1422                ret = DEPENDENCY_SUPPORTED;
1423#else
1424                ret = DEPENDENCY_NOT_SUPPORTED;
1425#endif
1426            }
1427            break;
1428        case 1:
1429            {
1430#if defined(DEP2)
1431                ret = DEPENDENCY_SUPPORTED;
1432#else
1433                ret = DEPENDENCY_NOT_SUPPORTED;
1434#endif
1435            }
1436            break;
1437        case 2:
1438            {
1439#if defined(DEP1)
1440                ret = DEPENDENCY_SUPPORTED;
1441#else
1442                ret = DEPENDENCY_NOT_SUPPORTED;
1443#endif
1444            }
1445            break;'''
1446        self.assertEqual(dep_check_code, expect_dep_check_code)
1447        self.assertEqual(len(unique_dependencies), 3)
1448        self.assertEqual(stream.getvalue(),
1449                         'depends_on:0:1\ndepends_on:1:2\ndepends_on:2:0\n')
1450
1451
1452class WriteParams(TestCase):
1453    """
1454    Test Suite for testing write_parameters().
1455    """
1456
1457    def test_no_params(self):
1458        """
1459        Test with empty test_args
1460        :return:
1461        """
1462        stream = StringIOWrapper('test_suite_ut.data', '')
1463        unique_expressions = []
1464        expression_code = write_parameters(stream, [], [], unique_expressions)
1465        self.assertEqual(len(unique_expressions), 0)
1466        self.assertEqual(expression_code, '')
1467        self.assertEqual(stream.getvalue(), '\n')
1468
1469    def test_no_exp_param(self):
1470        """
1471        Test when there is no macro or expression in the params.
1472        :return:
1473        """
1474        stream = StringIOWrapper('test_suite_ut.data', '')
1475        unique_expressions = []
1476        expression_code = write_parameters(stream, ['"Yahoo"', '"abcdef00"',
1477                                                    '0'],
1478                                           ['char*', 'hex', 'int'],
1479                                           unique_expressions)
1480        self.assertEqual(len(unique_expressions), 0)
1481        self.assertEqual(expression_code, '')
1482        self.assertEqual(stream.getvalue(),
1483                         ':char*:"Yahoo":hex:"abcdef00":int:0\n')
1484
1485    def test_hex_format_int_param(self):
1486        """
1487        Test int parameter in hex format.
1488        :return:
1489        """
1490        stream = StringIOWrapper('test_suite_ut.data', '')
1491        unique_expressions = []
1492        expression_code = write_parameters(stream,
1493                                           ['"Yahoo"', '"abcdef00"', '0xAA'],
1494                                           ['char*', 'hex', 'int'],
1495                                           unique_expressions)
1496        self.assertEqual(len(unique_expressions), 0)
1497        self.assertEqual(expression_code, '')
1498        self.assertEqual(stream.getvalue(),
1499                         ':char*:"Yahoo":hex:"abcdef00":int:0xAA\n')
1500
1501    def test_with_exp_param(self):
1502        """
1503        Test when there is macro or expression in the params.
1504        :return:
1505        """
1506        stream = StringIOWrapper('test_suite_ut.data', '')
1507        unique_expressions = []
1508        expression_code = write_parameters(stream,
1509                                           ['"Yahoo"', '"abcdef00"', '0',
1510                                            'MACRO1', 'MACRO2', 'MACRO3'],
1511                                           ['char*', 'hex', 'int',
1512                                            'int', 'int', 'int'],
1513                                           unique_expressions)
1514        self.assertEqual(len(unique_expressions), 3)
1515        self.assertEqual(unique_expressions, ['MACRO1', 'MACRO2', 'MACRO3'])
1516        expected_expression_code = '''
1517        case 0:
1518            {
1519                *out_value = MACRO1;
1520            }
1521            break;
1522        case 1:
1523            {
1524                *out_value = MACRO2;
1525            }
1526            break;
1527        case 2:
1528            {
1529                *out_value = MACRO3;
1530            }
1531            break;'''
1532        self.assertEqual(expression_code, expected_expression_code)
1533        self.assertEqual(stream.getvalue(),
1534                         ':char*:"Yahoo":hex:"abcdef00":int:0:exp:0:exp:1'
1535                         ':exp:2\n')
1536
1537    def test_with_repeat_calls(self):
1538        """
1539        Test when write_parameter() is called with same macro or expression.
1540        :return:
1541        """
1542        stream = StringIOWrapper('test_suite_ut.data', '')
1543        unique_expressions = []
1544        expression_code = ''
1545        expression_code += write_parameters(stream,
1546                                            ['"Yahoo"', 'MACRO1', 'MACRO2'],
1547                                            ['char*', 'int', 'int'],
1548                                            unique_expressions)
1549        expression_code += write_parameters(stream,
1550                                            ['"abcdef00"', 'MACRO2', 'MACRO3'],
1551                                            ['hex', 'int', 'int'],
1552                                            unique_expressions)
1553        expression_code += write_parameters(stream,
1554                                            ['0', 'MACRO3', 'MACRO1'],
1555                                            ['int', 'int', 'int'],
1556                                            unique_expressions)
1557        self.assertEqual(len(unique_expressions), 3)
1558        self.assertEqual(unique_expressions, ['MACRO1', 'MACRO2', 'MACRO3'])
1559        expected_expression_code = '''
1560        case 0:
1561            {
1562                *out_value = MACRO1;
1563            }
1564            break;
1565        case 1:
1566            {
1567                *out_value = MACRO2;
1568            }
1569            break;
1570        case 2:
1571            {
1572                *out_value = MACRO3;
1573            }
1574            break;'''
1575        self.assertEqual(expression_code, expected_expression_code)
1576        expected_data_file = ''':char*:"Yahoo":exp:0:exp:1
1577:hex:"abcdef00":exp:1:exp:2
1578:int:0:exp:2:exp:0
1579'''
1580        self.assertEqual(stream.getvalue(), expected_data_file)
1581
1582
1583class GenTestSuiteDependenciesChecks(TestCase):
1584    """
1585    Test suite for testing gen_suite_dep_checks()
1586    """
1587    def test_empty_suite_dependencies(self):
1588        """
1589        Test with empty suite_dependencies list.
1590
1591        :return:
1592        """
1593        dep_check_code, expression_code = \
1594            gen_suite_dep_checks([], 'DEP_CHECK_CODE', 'EXPRESSION_CODE')
1595        self.assertEqual(dep_check_code, 'DEP_CHECK_CODE')
1596        self.assertEqual(expression_code, 'EXPRESSION_CODE')
1597
1598    def test_suite_dependencies(self):
1599        """
1600        Test with suite_dependencies list.
1601
1602        :return:
1603        """
1604        dep_check_code, expression_code = \
1605            gen_suite_dep_checks(['SUITE_DEP'], 'DEP_CHECK_CODE',
1606                                 'EXPRESSION_CODE')
1607        expected_dep_check_code = '''
1608#if defined(SUITE_DEP)
1609DEP_CHECK_CODE
1610#endif
1611'''
1612        expected_expression_code = '''
1613#if defined(SUITE_DEP)
1614EXPRESSION_CODE
1615#endif
1616'''
1617        self.assertEqual(dep_check_code, expected_dep_check_code)
1618        self.assertEqual(expression_code, expected_expression_code)
1619
1620    def test_no_dep_no_exp(self):
1621        """
1622        Test when there are no dependency and expression code.
1623        :return:
1624        """
1625        dep_check_code, expression_code = gen_suite_dep_checks([], '', '')
1626        self.assertEqual(dep_check_code, '')
1627        self.assertEqual(expression_code, '')
1628
1629
1630class GenFromTestData(TestCase):
1631    """
1632    Test suite for gen_from_test_data()
1633    """
1634
1635    @staticmethod
1636    @patch("generate_test_code.write_dependencies")
1637    @patch("generate_test_code.write_parameters")
1638    @patch("generate_test_code.gen_suite_dep_checks")
1639    def test_intermediate_data_file(func_mock1,
1640                                    write_parameters_mock,
1641                                    write_dependencies_mock):
1642        """
1643        Test that intermediate data file is written with expected data.
1644        :return:
1645        """
1646        data = '''
1647My test
1648depends_on:DEP1
1649func1:0
1650'''
1651        data_f = StringIOWrapper('test_suite_ut.data', data)
1652        out_data_f = StringIOWrapper('test_suite_ut.datax', '')
1653        func_info = {'test_func1': (1, ('int',))}
1654        suite_dependencies = []
1655        write_parameters_mock.side_effect = write_parameters
1656        write_dependencies_mock.side_effect = write_dependencies
1657        func_mock1.side_effect = gen_suite_dep_checks
1658        gen_from_test_data(data_f, out_data_f, func_info, suite_dependencies)
1659        write_dependencies_mock.assert_called_with(out_data_f,
1660                                                   ['DEP1'], ['DEP1'])
1661        write_parameters_mock.assert_called_with(out_data_f, ['0'],
1662                                                 ('int',), [])
1663        expected_dep_check_code = '''
1664        case 0:
1665            {
1666#if defined(DEP1)
1667                ret = DEPENDENCY_SUPPORTED;
1668#else
1669                ret = DEPENDENCY_NOT_SUPPORTED;
1670#endif
1671            }
1672            break;'''
1673        func_mock1.assert_called_with(
1674            suite_dependencies, expected_dep_check_code, '')
1675
1676    def test_function_not_found(self):
1677        """
1678        Test that AssertError is raised when function info in not found.
1679        :return:
1680        """
1681        data = '''
1682My test
1683depends_on:DEP1
1684func1:0
1685'''
1686        data_f = StringIOWrapper('test_suite_ut.data', data)
1687        out_data_f = StringIOWrapper('test_suite_ut.datax', '')
1688        func_info = {'test_func2': (1, ('int',))}
1689        suite_dependencies = []
1690        self.assertRaises(GeneratorInputError, gen_from_test_data,
1691                          data_f, out_data_f, func_info, suite_dependencies)
1692
1693    def test_different_func_args(self):
1694        """
1695        Test that AssertError is raised when no. of parameters and
1696        function args differ.
1697        :return:
1698        """
1699        data = '''
1700My test
1701depends_on:DEP1
1702func1:0
1703'''
1704        data_f = StringIOWrapper('test_suite_ut.data', data)
1705        out_data_f = StringIOWrapper('test_suite_ut.datax', '')
1706        func_info = {'test_func2': (1, ('int', 'hex'))}
1707        suite_dependencies = []
1708        self.assertRaises(GeneratorInputError, gen_from_test_data, data_f,
1709                          out_data_f, func_info, suite_dependencies)
1710
1711    def test_output(self):
1712        """
1713        Test that intermediate data file is written with expected data.
1714        :return:
1715        """
1716        data = '''
1717My test 1
1718depends_on:DEP1
1719func1:0:0xfa:MACRO1:MACRO2
1720
1721My test 2
1722depends_on:DEP1:DEP2
1723func2:"yahoo":88:MACRO1
1724'''
1725        data_f = StringIOWrapper('test_suite_ut.data', data)
1726        out_data_f = StringIOWrapper('test_suite_ut.datax', '')
1727        func_info = {'test_func1': (0, ('int', 'int', 'int', 'int')),
1728                     'test_func2': (1, ('char*', 'int', 'int'))}
1729        suite_dependencies = []
1730        dep_check_code, expression_code = \
1731            gen_from_test_data(data_f, out_data_f, func_info,
1732                               suite_dependencies)
1733        expected_dep_check_code = '''
1734        case 0:
1735            {
1736#if defined(DEP1)
1737                ret = DEPENDENCY_SUPPORTED;
1738#else
1739                ret = DEPENDENCY_NOT_SUPPORTED;
1740#endif
1741            }
1742            break;
1743        case 1:
1744            {
1745#if defined(DEP2)
1746                ret = DEPENDENCY_SUPPORTED;
1747#else
1748                ret = DEPENDENCY_NOT_SUPPORTED;
1749#endif
1750            }
1751            break;'''
1752        expected_data = '''My test 1
1753depends_on:0
17540:int:0:int:0xfa:exp:0:exp:1
1755
1756My test 2
1757depends_on:0:1
17581:char*:"yahoo":int:88:exp:0
1759
1760'''
1761        expected_expression_code = '''
1762        case 0:
1763            {
1764                *out_value = MACRO1;
1765            }
1766            break;
1767        case 1:
1768            {
1769                *out_value = MACRO2;
1770            }
1771            break;'''
1772        self.assertEqual(dep_check_code, expected_dep_check_code)
1773        self.assertEqual(out_data_f.getvalue(), expected_data)
1774        self.assertEqual(expression_code, expected_expression_code)
1775
1776
1777if __name__ == '__main__':
1778    unittest_main()
1779