1# Copyright 2019 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""Tests for code.""" 15 16from __future__ import absolute_import 17from __future__ import division 18from __future__ import print_function 19from absl.testing import absltest 20from absl.testing import parameterized 21from clang import cindex 22from com_google_sandboxed_api.sandboxed_api.tools.python_generator import code 23from com_google_sandboxed_api.sandboxed_api.tools.python_generator import code_test_util 24 25CODE = """ 26typedef int(fun*)(int,int); 27extern "C" int function_a(int x, int y) { return x + y; } 28extern "C" int function_b(int a, int b) { return a + b; } 29 30struct a { 31 void (*fun_ptr)(char, long); 32} 33""" 34 35 36def analyze_string( 37 content, path='tmp.cc', limit_scan_depth=False, func_names=None 38): 39 """Returns Analysis object for in memory content.""" 40 return analyze_strings(path, [(path, content)], limit_scan_depth, func_names) 41 42 43def analyze_strings( 44 path, unsaved_files, limit_scan_depth=False, func_names=None 45): 46 """Returns Analysis object for in memory content.""" 47 return code.Analyzer._analyze_file_for_tu( 48 path, None, False, unsaved_files, limit_scan_depth, func_names 49 ) 50 51 52class CodeAnalysisTest(parameterized.TestCase): 53 54 def testInMemoryFile(self): 55 translation_unit = analyze_string(CODE) 56 self.assertIsNotNone(translation_unit._tu.cursor) 57 58 def testSimpleASTTraversal(self): 59 translation_unit = analyze_string(CODE) 60 61 structs = 0 62 functions = 0 63 params = 0 64 typedefs = 0 65 66 for cursor in translation_unit._walk_preorder(): 67 if cursor.kind == cindex.CursorKind.FUNCTION_DECL: 68 functions += 1 69 elif cursor.kind == cindex.CursorKind.STRUCT_DECL: 70 structs += 1 71 elif cursor.kind == cindex.CursorKind.PARM_DECL: 72 params += 1 73 elif cursor.kind == cindex.CursorKind.TYPEDEF_DECL: 74 typedefs += 1 75 76 self.assertEqual(functions, 2) 77 self.assertEqual(structs, 1) 78 self.assertEqual(params, 8) 79 self.assertEqual(typedefs, 1) 80 81 def testParseSkipFunctionBodies(self): 82 function_body = 'extern "C" int function(bool a1) { return a1 ? 1 : 2; }' 83 translation_unit = analyze_string(function_body) 84 for cursor in translation_unit._walk_preorder(): 85 if cursor.kind == cindex.CursorKind.FUNCTION_DECL: 86 # cursor.get_definition() is None when we skip parsing function bodies 87 self.assertIsNone(cursor.get_definition()) 88 89 def testExternC(self): 90 translation_unit = analyze_string('extern "C" int function(char* a);') 91 cursor_kinds = [ 92 x.kind 93 for x in translation_unit._walk_preorder() 94 if x.kind != cindex.CursorKind.MACRO_DEFINITION 95 ] 96 for kind in [ 97 cindex.CursorKind.TRANSLATION_UNIT, 98 cindex.CursorKind.FUNCTION_DECL, 99 cindex.CursorKind.PARM_DECL, 100 ]: 101 self.assertIn(kind, cursor_kinds) 102 self.assertTrue( 103 cindex.CursorKind.LINKAGE_SPEC in cursor_kinds 104 # Older libclang versions to not have a cursor type for linkage specs 105 or cindex.CursorKind.UNEXPOSED_DECL in cursor_kinds 106 ) 107 108 @parameterized.named_parameters( 109 ('1:', '/tmp/test.h', 'tmp', 'tmp/test.h'), 110 ('2:', '/a/b/c/d/tmp/test.h', 'c/d', 'c/d/tmp/test.h'), 111 ('3:', '/tmp/test.h', None, '/tmp/test.h'), 112 ('4:', '/tmp/test.h', '', '/tmp/test.h'), 113 ('5:', '/tmp/test.h', 'xxx', 'xxx/test.h'), 114 ) 115 def testGetIncludes(self, path, prefix, expected): 116 function_body = 'extern "C" int function(bool a1) { return a1 ? 1 : 2; }' 117 translation_unit = analyze_string(function_body) 118 for cursor in translation_unit._walk_preorder(): 119 if cursor.kind == cindex.CursorKind.FUNCTION_DECL: 120 fn = code.Function(translation_unit, cursor) 121 fn.get_absolute_path = lambda: path 122 self.assertEqual(fn.get_include_path(prefix), expected) 123 124 def testCodeGeneratorOutput(self): 125 body = """ 126 extern "C" { 127 int function_a(int x, int y) { return x + y; } 128 129 int types_1(bool a0, unsigned char a1, char a2, unsigned short a3, short a4); 130 int types_2(int a0, unsigned int a1, long a2, unsigned long a3); 131 int types_3(long long a0, unsigned long long a1, float a2, double a3); 132 int types_4(signed char a0, signed short a1, signed int a2, signed long a3); 133 int types_5(signed long long a0, long double a1); 134 void types_6(char* a0); 135 } 136 """ 137 functions = [ 138 'function_a', 139 'types_1', 140 'types_2', 141 'types_3', 142 'types_4', 143 'types_5', 144 'types_6', 145 ] 146 generator = code.Generator([analyze_string(body, func_names=functions)]) 147 result = generator.generate('Test', 'sapi::Tests', None, None) 148 self.assertMultiLineEqual(code_test_util.CODE_GOLD, result) 149 150 def testElaboratedArgument(self): 151 body = """ 152 struct x { int a; }; 153 extern "C" int function(struct x a) { return a.a; } 154 """ 155 generator = code.Generator([analyze_string(body, func_names=['function'])]) 156 with self.assertRaisesRegex(ValueError, r'Elaborate.*mapped.*'): 157 generator.generate('Test', 'sapi::Tests', None, None) 158 159 def testElaboratedArgument2(self): 160 body = """ 161 typedef struct { int a; char b; } x; 162 extern "C" int function(x a) { return a.a; } 163 """ 164 generator = code.Generator([analyze_string(body, func_names=['function'])]) 165 with self.assertRaisesRegex(ValueError, r'Elaborate.*mapped.*'): 166 generator.generate('Test', 'sapi::Tests', None, None) 167 168 def testGetMappedType(self): 169 body = """ 170 typedef unsigned int uint; 171 typedef uint* uintp; 172 extern "C" uint function(uintp a) { return *a; } 173 """ 174 generator = code.Generator([analyze_string(body)]) 175 result = generator.generate('Test', 'sapi::Tests', None, None) 176 self.assertMultiLineEqual(code_test_util.CODE_GOLD_MAPPED, result) 177 178 @parameterized.named_parameters( 179 ('1:', '/tmp/test.h', '_TMP_TEST_H_'), 180 ('2:', 'tmp/te-st.h', 'TMP_TE_ST_H_'), 181 ('3:', 'tmp/te-st.h.gen', 'TMP_TE_ST_H_'), 182 ('4:', 'xx/genfiles/tmp/te-st.h', 'TMP_TE_ST_H_'), 183 ('5:', 'xx/genfiles/tmp/te-st.h.gen', 'TMP_TE_ST_H_'), 184 ('6:', 'xx/genfiles/.gen/tmp/te-st.h', '_GEN_TMP_TE_ST_H_'), 185 ) 186 def testGetHeaderGuard(self, path, expected): 187 self.assertEqual(code.get_header_guard(path), expected) 188 189 @parameterized.named_parameters( 190 ( 191 'function with return value and arguments', 192 'extern "C" int function(bool arg_bool, char* arg_ptr);', 193 ['arg_bool', 'arg_ptr'], 194 ), 195 ( 196 'function without return value and no arguments', 197 'extern "C" void function();', 198 [], 199 ), 200 ) 201 def testArgumentNames(self, body, names): 202 generator = code.Generator([analyze_string(body)]) 203 functions = generator._get_functions() 204 self.assertLen(functions, 1) 205 self.assertLen(functions[0].argument_types, len(names)) 206 # Extra check for generation, in case rendering throws error for this test. 207 generator.generate('Test', 'sapi::Tests', None, None) 208 for t in functions[0].argument_types: 209 self.assertIn(t.name, names) 210 211 def testStaticFunctions(self): 212 body = 'static int function() { return 7; };' 213 generator = code.Generator([analyze_string(body)]) 214 self.assertEmpty(generator._get_functions()) 215 216 def testEnumGeneration(self): 217 body = """ 218 enum ProcessStatus { 219 OK = 0, 220 ERROR = 1, 221 }; 222 223 extern "C" ProcessStatus ProcessDatapoint(ProcessStatus status) { 224 return status; 225 } 226 """ 227 generator = code.Generator([analyze_string(body)]) 228 result = generator.generate('Test', 'sapi::Tests', None, None) 229 self.assertMultiLineEqual(code_test_util.CODE_ENUM_GOLD, result) 230 231 def testTypeEq(self): 232 body = """ 233 typedef unsigned int uint; 234 extern "C" void function(uint a1, uint a2, char a3); 235 """ 236 generator = code.Generator([analyze_string(body)]) 237 functions = generator._get_functions() 238 self.assertLen(functions, 1) 239 240 args = functions[0].arguments() 241 self.assertLen(args, 3) 242 self.assertEqual(args[0], args[1]) 243 self.assertNotEqual(args[0], args[2]) 244 self.assertNotEqual(args[1], args[2]) 245 246 self.assertLen(set(args), 2) 247 # Extra check for generation, in case rendering throws error for this test. 248 generator.generate('Test', 'sapi::Tests', None, None) 249 250 def testTypedefRelatedTypes(self): 251 body = """ 252 typedef unsigned int uint; 253 typedef uint* uint_p; 254 typedef uint_p* uint_pp; 255 256 typedef struct data { 257 int a; 258 int b; 259 } data_s; 260 typedef data_s* data_p; 261 262 extern "C" uint function_using_typedefs(uint_p a1, uint_pp a2, data_p a3); 263 """ 264 generator = code.Generator([analyze_string(body)]) 265 functions = generator._get_functions() 266 self.assertLen(functions, 1) 267 268 args = functions[0].arguments() 269 self.assertLen(args, 3) 270 271 types = args[0].get_related_types() 272 names = [t._clang_type.spelling for t in types] 273 self.assertLen(types, 2) 274 self.assertSameElements(names, ['uint_p', 'uint']) 275 276 types = args[1].get_related_types() 277 names = [t._clang_type.spelling for t in types] 278 self.assertLen(types, 3) 279 self.assertSameElements(names, ['uint_pp', 'uint_p', 'uint']) 280 281 types = args[2].get_related_types() 282 names = [t._clang_type.spelling for t in types] 283 self.assertLen(types, 2) 284 self.assertSameElements(names, ['data_s', 'data_p']) 285 286 # Extra check for generation, in case rendering throws error for this test. 287 generator.generate('Test', 'sapi::Tests', None, None) 288 289 def testTypedefDuplicateType(self): 290 body = """ 291 typedef struct data { 292 int a; 293 int b; 294 } data_s; 295 296 struct s { 297 struct data* f1; 298 }; 299 300 extern "C" uint function_using_typedefs(struct s* a1, data_s* a2); 301 """ 302 generator = code.Generator([analyze_string(body)]) 303 functions = generator._get_functions() 304 self.assertLen(functions, 1) 305 306 args = functions[0].arguments() 307 self.assertLen(args, 2) 308 309 types = generator._get_related_types() 310 self.assertLen(generator.translation_units[0].types_to_skip, 1) 311 312 names = [t._clang_type.spelling for t in types] 313 self.assertSameElements(['data_s', 's'], names) 314 315 # Extra check for generation, in case rendering throws error for this test. 316 generator.generate('Test', 'sapi::Tests', None, None) 317 318 def testStructureRelatedTypes(self): 319 body = """ 320 typedef unsigned int uint; 321 322 typedef struct { 323 uint a; 324 struct { 325 int a; 326 int b; 327 } b; 328 } struct_1; 329 330 struct struct_2 { 331 uint a; 332 char b; 333 struct_1* c; 334 }; 335 336 typedef struct a { 337 int b; 338 } struct_a; 339 340 extern "C" int function_using_structures(struct struct_2* a1, struct_1* a2, 341 struct_a* a3); 342 """ 343 generator = code.Generator([analyze_string(body)]) 344 functions = generator._get_functions() 345 self.assertLen(functions, 1) 346 347 args = functions[0].arguments() 348 self.assertLen(args, 3) 349 350 types = args[0].get_related_types() 351 names = [t._clang_type.spelling for t in types] 352 self.assertLen(types, 3) 353 self.assertSameElements(names, ['struct_2', 'uint', 'struct_1']) 354 355 types = args[1].get_related_types() 356 names = [t._clang_type.spelling for t in types] 357 self.assertLen(types, 2) 358 self.assertSameElements(names, ['struct_1', 'uint']) 359 360 names = [t._clang_type.spelling for t in generator._get_related_types()] 361 self.assertEqual(names, ['uint', 'struct_1', 'struct_2', 'struct_a']) 362 363 types = args[2].get_related_types() 364 self.assertLen(types, 1) 365 366 # Extra check for generation, in case rendering throws error for this test. 367 generator.generate('Test', 'sapi::Tests', None, None) 368 369 def testUnionRelatedTypes(self): 370 body = """ 371 typedef unsigned int uint; 372 373 typedef union { 374 uint a; 375 union { 376 int a; 377 int b; 378 } b; 379 } union_1; 380 381 union union_2 { 382 uint a; 383 char b; 384 union_1* c; 385 }; 386 387 extern "C" int function_using_unions(union union_2* a1, union_1* a2); 388 """ 389 generator = code.Generator([analyze_string(body)]) 390 functions = generator._get_functions() 391 self.assertLen(functions, 1) 392 393 args = functions[0].arguments() 394 self.assertLen(args, 2) 395 396 types = args[0].get_related_types() 397 names = [t._clang_type.spelling for t in types] 398 self.assertLen(types, 3) 399 self.assertSameElements(names, ['union_2', 'uint', 'union_1']) 400 401 types = args[1].get_related_types() 402 names = [t._clang_type.spelling for t in types] 403 self.assertLen(types, 2) 404 self.assertSameElements(names, ['union_1', 'uint']) 405 406 # Extra check for generation, in case rendering throws error for this test. 407 generator.generate('Test', 'sapi::Tests', None, None) 408 409 def testFunctionPointerRelatedTypes(self): 410 body = """ 411 typedef unsigned int uint; 412 typedef unsigned char uchar; 413 typedef uint (*funcp)(uchar, uchar); 414 415 struct struct_1 { 416 uint (*func)(uchar); 417 int a; 418 }; 419 420 extern "C" void function(struct struct_1* a1, funcp a2); 421 """ 422 generator = code.Generator([analyze_string(body)]) 423 functions = generator._get_functions() 424 self.assertLen(functions, 1) 425 426 args = functions[0].arguments() 427 self.assertLen(args, 2) 428 429 types = args[0].get_related_types() 430 names = [t._clang_type.spelling for t in types] 431 self.assertLen(types, 3) 432 self.assertSameElements(names, ['struct_1', 'uint', 'uchar']) 433 434 types = args[1].get_related_types() 435 names = [t._clang_type.spelling for t in types] 436 self.assertLen(types, 3) 437 self.assertSameElements(names, ['funcp', 'uint', 'uchar']) 438 439 # Extra check for generation, in case rendering throws error for this test. 440 generator.generate('Test', 'sapi::Tests', None, None) 441 442 def testForwardDeclaration(self): 443 body = """ 444 struct struct_6_def; 445 typedef struct struct_6_def struct_6; 446 typedef struct_6* struct_6p; 447 typedef void (*function_p3)(struct_6p); 448 struct struct_6_def { 449 function_p3 fn; 450 }; 451 452 extern "C" void function_using_type_loop(struct_6p a1); 453 """ 454 generator = code.Generator([analyze_string(body)]) 455 functions = generator._get_functions() 456 self.assertLen(functions, 1) 457 458 args = functions[0].arguments() 459 self.assertLen(args, 1) 460 461 types = args[0].get_related_types() 462 names = [t._clang_type.spelling for t in types] 463 self.assertLen(types, 4) 464 self.assertSameElements( 465 names, ['struct_6p', 'struct_6', 'struct_6_def', 'function_p3'] 466 ) 467 468 self.assertLen(generator.translation_units, 1) 469 self.assertLen(generator.translation_units[0].forward_decls, 1) 470 471 t = next(x for x in types if x._clang_type.spelling == 'struct_6_def') 472 self.assertIn(t, generator.translation_units[0].forward_decls) 473 474 names = [t._clang_type.spelling for t in generator._get_related_types()] 475 self.assertEqual( 476 names, ['struct_6', 'struct_6p', 'function_p3', 'struct_6_def'] 477 ) 478 479 # Extra check for generation, in case rendering throws error for this test. 480 forward_decls = generator._get_forward_decls(generator._get_related_types()) 481 self.assertLen(forward_decls, 1) 482 self.assertEqual(forward_decls[0], 'struct struct_6_def;') 483 generator.generate('Test', 'sapi::Tests', None, None) 484 485 def testEnumRelatedTypes(self): 486 body = """ 487 enum Enumeration { ONE, TWO, THREE }; 488 typedef enum Numbers { UNKNOWN, FIVE = 5, SE7EN = 7 } Nums; 489 typedef enum { SIX = 6, TEN = 10 } SixOrTen; 490 enum class Color : long long { RED, GREEN = 20, BLUE }; // NOLINT 491 enum struct Direction { LEFT = 'l', RIGHT = 'r' }; 492 enum __rlimit_resource { RLIMIT_CPU = 0, RLIMIT_MEM = 1}; 493 494 extern "C" int function_using_enums(Enumeration a1, SixOrTen a2, Color a3, 495 Direction a4, Nums a5, enum __rlimit_resource a6); 496 """ 497 generator = code.Generator([analyze_string(body)]) 498 functions = generator._get_functions() 499 self.assertLen(functions, 1) 500 501 args = functions[0].arguments() 502 self.assertLen(args, 6) 503 504 self.assertLen(args[0].get_related_types(), 1) 505 self.assertLen(args[1].get_related_types(), 1) 506 self.assertLen(args[2].get_related_types(), 1) 507 self.assertLen(args[3].get_related_types(), 1) 508 self.assertLen(args[4].get_related_types(), 1) 509 self.assertLen(args[5].get_related_types(), 1) 510 511 # Extra check for generation, in case rendering throws error for this test. 512 generator.generate('Test', 'sapi::Tests', None, None) 513 514 def testArrayAsParam(self): 515 body = """ 516 extern "C" int function_using_enums(char a[10], char *const __argv[]); 517 """ 518 generator = code.Generator([analyze_string(body)]) 519 functions = generator._get_functions() 520 self.assertLen(functions, 1) 521 522 args = functions[0].arguments() 523 self.assertLen(args, 2) 524 525 @parameterized.named_parameters( 526 ('uint < ushort ', 'assertLess', 1, 2), 527 ('uint < chr ', 'assertLess', 1, 3), 528 ('uint < uchar ', 'assertLess', 1, 4), 529 ('uint < u32 ', 'assertLess', 1, 5), 530 ('uint < ulong ', 'assertLess', 1, 6), 531 ('ushort < chr ', 'assertLess', 2, 3), 532 ('ushort < uchar ', 'assertLess', 2, 4), 533 ('ushort < u32 ', 'assertLess', 2, 5), 534 ('ushort < ulong ', 'assertLess', 2, 6), 535 ('chr < uchar ', 'assertLess', 3, 4), 536 ('chr < u32 ', 'assertLess', 3, 5), 537 ('chr < ulong ', 'assertLess', 3, 6), 538 ('uchar < u32 ', 'assertLess', 4, 5), 539 ('uchar < ulong ', 'assertLess', 4, 6), 540 ('u32 < ulong ', 'assertLess', 5, 6), 541 ('ushort > uint ', 'assertGreater', 2, 1), 542 ('chr > uint ', 'assertGreater', 3, 1), 543 ('uchar > uint ', 'assertGreater', 4, 1), 544 ('u32 > uint ', 'assertGreater', 5, 1), 545 ('ulong > uint ', 'assertGreater', 6, 1), 546 ('chr > ushort ', 'assertGreater', 3, 2), 547 ('uchar > ushort ', 'assertGreater', 4, 2), 548 ('u32 > ushort ', 'assertGreater', 5, 2), 549 ('ulong > ushort ', 'assertGreater', 6, 2), 550 ('uchar > chr ', 'assertGreater', 4, 3), 551 ('u32 > chr ', 'assertGreater', 5, 3), 552 ('ulong > chr ', 'assertGreater', 6, 3), 553 ('u32 > uchar ', 'assertGreater', 5, 4), 554 ('ulong > uchar ', 'assertGreater', 6, 4), 555 ('ulong > u32 ', 'assertGreater', 6, 5), 556 ) 557 def testTypeOrder(self, func, a1, a2): 558 """Checks if comparison functions of Type class work properly. 559 560 This is necessary for Generator._get_related_types to return types in 561 proper order, ready to be emitted in the generated file. To be more 562 specific: emitted types will be ordered in a way that would allow 563 compilation ie. if structure field type is a typedef, typedef definition 564 will end up before structure definition. 565 566 Args: 567 func: comparison assert to call 568 a1: function argument number to take the type to compare 569 a2: function argument number to take the type to compare 570 """ 571 572 file1_code = """ 573 typedef unsigned int uint; 574 #include "/f2.h" 575 typedef uint u32; 576 #include "/f3.h" 577 578 struct args { 579 u32 a; 580 uchar b; 581 ulong c; 582 ushort d; 583 chr e; 584 }; 585 extern "C" int function(struct args* a0, uint a1, ushort a2, chr a3, 586 uchar a4, u32 a5, ulong a6, struct args* a7); 587 """ 588 file2_code = """ 589 typedef unsigned short ushort; 590 #include "/f4.h" 591 typedef unsigned char uchar;""" 592 file3_code = 'typedef unsigned long ulong;' 593 file4_code = 'typedef char chr;' 594 files = [ 595 ('f1.h', file1_code), 596 ('/f2.h', file2_code), 597 ('/f3.h', file3_code), 598 ('/f4.h', file4_code), 599 ] 600 generator = code.Generator([analyze_strings('f1.h', files)]) 601 functions = generator._get_functions() 602 self.assertLen(functions, 1) 603 604 args = functions[0].arguments() 605 getattr(self, func)(args[a1], args[a2]) 606 # Extra check for generation, in case rendering throws error for this test. 607 generator.generate('Test', 'sapi::Tests', None, None) 608 609 def testFilterFunctionsFromInputFilesOnly(self): 610 file1_code = """ 611 #include "/f2.h" 612 613 extern "C" int function1(); 614 """ 615 file2_code = """ 616 extern "C" int function2(); 617 """ 618 619 files = [('f1.h', file1_code), ('/f2.h', file2_code)] 620 generator = code.Generator([analyze_strings('f1.h', files)]) 621 functions = generator._get_functions() 622 self.assertLen(functions, 2) 623 624 generator = code.Generator([analyze_strings('f1.h', files, True)]) 625 functions = generator._get_functions() 626 self.assertLen(functions, 1) 627 628 def testTypeToString(self): 629 body = """ 630 #define SIZE 1024 631 typedef unsigned int uint; 632 633 typedef struct { 634 #if SOME_DEFINE >= 12 \ 635 && SOME_OTHER == 13 636 uint a; 637 #else 638 uint aa; 639 #endif 640 struct { 641 uint a; 642 int b; 643 char c[SIZE]; 644 } b; 645 } struct_1; 646 647 extern "C" int function_using_structures(struct_1* a1); 648 """ 649 650 # pylint: disable=trailing-whitespace 651 expected = """typedef struct { 652#if SOME_DEFINE >= 12 && SOME_OTHER == 13 653\tuint a ; 654#else 655\tuint aa ; 656#endif 657\tstruct { 658\t\tuint a ; 659\t\tint b ; 660\t\tchar c [ SIZE ] ; 661\t} b ; 662} struct_1""" 663 generator = code.Generator([analyze_string(body)]) 664 functions = generator._get_functions() 665 self.assertLen(functions, 1) 666 667 types = generator._get_related_types() 668 self.assertLen(types, 2) 669 self.assertEqual('typedef unsigned int uint', types[0].stringify()) 670 self.assertMultiLineEqual(expected, types[1].stringify()) 671 672 # Extra check for generation, in case rendering throws error for this test. 673 generator.generate('Test', 'sapi::Tests', None, None) 674 675 def testCollectDefines(self): 676 body = """ 677 #define SIZE 1024 678 #define NOT_USED 7 679 #define SIZE2 2*1024 680 #define SIZE3 1337 681 #define SIZE4 10 682 struct test { 683 int a[SIZE]; 684 char b[SIZE2]; 685 float c[777]; 686 int (*d)[SIZE3*SIZE4]; 687 }; 688 extern "C" int function_1(struct test* a1); 689 """ 690 generator = code.Generator([analyze_string(body)]) 691 self.assertLen(generator.translation_units, 1) 692 693 generator._get_related_types() 694 tu = generator.translation_units[0] 695 tu.get_functions() 696 697 self.assertLen(tu.required_defines, 4) 698 defines = generator._get_defines() 699 self.assertLen(defines, 4) 700 self.assertIn('#define SIZE 1024', defines) 701 self.assertIn('#define SIZE2 2 * 1024', defines) 702 self.assertIn('#define SIZE3 1337', defines) 703 self.assertIn('#define SIZE4 10', defines) 704 705 # Extra check for generation, in case rendering throws error for this test. 706 generator.generate('Test', 'sapi::Tests', None, None) 707 708 def testYaraCase(self): 709 body = """ 710 #define YR_ALIGN(n) __attribute__((aligned(n))) 711 #define DECLARE_REFERENCE(type, name) union { \ 712 type name; \ 713 int64_t name##_; \ 714 } YR_ALIGN(8) 715 struct YR_NAMESPACE { 716 int32_t t_flags[1337]; 717 DECLARE_REFERENCE(char*, name); 718 }; 719 720 extern "C" int function_1(struct YR_NAMESPACE* a1); 721 """ 722 generator = code.Generator([analyze_string(body)]) 723 self.assertLen(generator.translation_units, 1) 724 725 generator._get_related_types() 726 tu = generator.translation_units[0] 727 tu.get_functions() 728 729 self.assertLen(tu.required_defines, 2) 730 defines = generator._get_defines() 731 # _get_defines will add dependant defines to tu.required_defines 732 self.assertLen(defines, 2) 733 gold = '#define DECLARE_REFERENCE(' 734 # DECLARE_REFERENCE must be second to pass this test 735 self.assertTrue(defines[1].startswith(gold)) 736 737 # Extra check for generation, in case rendering throws error for this test. 738 generator.generate('Test', 'sapi::Tests', None, None) 739 740 def testDoubleFunction(self): 741 body = """ 742 extern "C" int function_1(int a); 743 extern "C" int function_1(int a) { 744 return a + 1; 745 }; 746 """ 747 generator = code.Generator([analyze_string(body)]) 748 self.assertLen(generator.translation_units, 1) 749 750 tu = generator.translation_units[0] 751 tu._process() 752 753 self.assertLen(tu.functions, 1) 754 755 # Extra check for generation, in case rendering throws error for this test. 756 generator.generate('Test', 'sapi::Tests', None, None) 757 758 def testDefineStructBody(self): 759 body = """ 760 #define STRUCT_BODY \ 761 int a; \ 762 char b; \ 763 long c 764 struct test { 765 STRUCT_BODY; 766 }; 767 extern "C" void function(struct test* a1); 768 """ 769 770 generator = code.Generator([analyze_string(body)]) 771 self.assertLen(generator.translation_units, 1) 772 773 # initialize all internal data 774 generator.generate('Test', 'sapi::Tests', None, None) 775 tu = generator.translation_units[0] 776 777 self.assertLen(tu.functions, 1) 778 self.assertLen(tu.required_defines, 1) 779 780 def testJpegTurboCase(self): 781 body = """ 782 typedef short JCOEF; 783 #define DCTSIZE2 1024 784 typedef JCOEF JBLOCK[DCTSIZE2]; 785 786 extern "C" void function(JBLOCK* a); 787 """ 788 generator = code.Generator([analyze_string(body)]) 789 self.assertLen(generator.translation_units, 1) 790 791 # initialize all internal data 792 generator.generate('Test', 'sapi::Tests', None, None) 793 794 tu = generator.translation_units[0] 795 self.assertLen(tu.functions, 1) 796 self.assertLen(generator._get_defines(), 1) 797 self.assertLen(generator._get_related_types(), 2) 798 799 def testMultipleTypesWhenConst(self): 800 body = """ 801 struct Instance { 802 void* instance = nullptr; 803 void* state_memory = nullptr; 804 void* scratch_memory = nullptr; 805 }; 806 807 extern "C" void function1(Instance* a); 808 extern "C" void function2(const Instance* a); 809 """ 810 generator = code.Generator([analyze_string(body)]) 811 self.assertLen(generator.translation_units, 1) 812 813 # Initialize all internal data 814 generator.generate('Test', 'sapi::Tests', None, None) 815 816 tu = generator.translation_units[0] 817 self.assertLen(tu.functions, 2) 818 self.assertLen(generator._get_related_types(), 1) 819 820 def testReference(self): 821 body = """ 822 struct Instance { 823 int a; 824 }; 825 826 void Function1(Instance& a, Instance&& a); 827 """ 828 generator = code.Generator([analyze_string(body)]) 829 self.assertLen(generator.translation_units, 1) 830 831 # Initialize all internal data 832 generator.generate('Test', 'sapi::Tests', None, None) 833 834 tu = generator.translation_units[0] 835 self.assertLen(tu.functions, 1) 836 837 # this will return 0 related types because function will be mangled and 838 # filtered out by generator 839 self.assertEmpty(generator._get_related_types()) 840 self.assertLen(next(iter(tu.functions)).get_related_types(), 1) 841 842 def testCppHeader(self): 843 path = 'tmp.h' 844 content = """ 845 int sum(int a, float b); 846 847 extern "C" int sum(int a, float b); 848 """ 849 unsaved_files = [(path, content)] 850 generator = code.Generator([analyze_strings(path, unsaved_files)]) 851 # Initialize all internal data 852 generator.generate('Test', 'sapi::Tests', None, None) 853 854 # generator should filter out mangled function 855 functions = generator._get_functions() 856 self.assertLen(functions, 1) 857 858 tu = generator.translation_units[0] 859 functions = tu.get_functions() 860 self.assertLen(functions, 2) 861 862 mangled_names = [f.cursor.mangled_name for f in functions] 863 self.assertSameElements(mangled_names, ['sum', '_Z3sumif']) 864 865 866if __name__ == '__main__': 867 absltest.main() 868