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