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