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