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