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