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