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