1#! /usr/bin/perl 2## 3## Copyright 2019 The Android Open Source Project 4## 5## Licensed under the Apache License, Version 2.0 (the "License"); 6## you may not use this file except in compliance with the License. 7## You may obtain a copy of the License at 8## 9## http://www.apache.org/licenses/LICENSE-2.0 10## 11## Unless required by applicable law or agreed to in writing, software 12## distributed under the License is distributed on an "AS IS" BASIS, 13## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14## See the License for the specific language governing permissions and 15## limitations under the License. 16 17use File::Basename; 18 19## mockcify version 20## 21## 0.7.1 Add tBTA_JV_STATUS return value 22## Remove unused compiler definition HAS_NO_BDROID_BUILDCFG 23## 24## 0.7.0 Comment out unused mock variables 25## 26## 0.6.3 Streamline inclusion for headers and source 27## 28## 0.6.2 Add tBTA_STATUS default value, Cpp type failure log 29## 30## 0.6.1 Add tBTA_SDP_STATUS default value 31## 32## 0.6.0 Replace `extern` with `include` for mock_function_count_map 33## 34## 0.5.0 Add compilation check 35## 36## 0.4.0 Second re-write 37## 38## 0.3.2 Remove pragma from source file 39## 40## 0.3.1 Statically link return value to prevent 'this' pointer in function 41## 42## 0.3.0 Re-write parser. 43## 44## 0.2.1 Compilation units only include types and a single related header file 45## Alphabetically sort functions by return value 46## Add non-primative return data values in structure 47## 48## 0.2.0 First version 49## 50my $VERSION = "0.7.1"; 51 52use diagnostics; 53use strict; 54use warnings; 55 56use lib "$ENV{ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/test/tool"; 57require 'mockcify_util.pl'; 58 59my $YEAR = "2023"; 60my $TOKEN = "MOCKCIFY_TOKEN"; 61my $MOCKCIFY_BRACKET_GROUP = "MOCKCIFY_BRACKET_GROUP"; 62my $CLANG_FORMAT = "/usr/bin/clang-format-13"; 63my $CC = "g++"; 64my $LIBCHROME = "../../../../external/libchrome/"; 65my $COMPILE_SCREEN_ENABLED = 0; 66 67my @structs; 68 69my %function_signature; 70my %function_return_types; 71my @function_names; 72my %function_params; 73my %function_param_names; 74my %function_param_types; 75 76sub clang_format { 77 return `$CLANG_FORMAT --style="{ColumnLimit: 10000, PointerAlignment: Left, PointerBindsToType: true, FixNamespaceComments: true }"`; 78} 79 80## Create a temp directory for any cruft 81my $TMPDIR="/tmp/mockcify"; 82system("mkdir -p $TMPDIR"); 83my $OUTDIR = "$TMPDIR/out/"; 84system("mkdir -p $OUTDIR"); 85my $INCDIR = "$TMPDIR/include/"; 86system("mkdir -p $INCDIR"); 87 88if (scalar(@ARGV == 0)) { 89 printf(STDERR "ERROR Must supply at least one argument\n"); 90 exit 1; 91} 92 93my $arg = shift @ARGV; 94## Check only argument for debug vector 95if ($arg =~ /--cla[ng]/) { 96 exit print clang_format(); 97} elsif ($arg =~ /--f[ilter]/) { 98 exit print read_stdin_and_filter_file(); 99} elsif ($arg =~ /--l[ines]/) { 100 exit print filter_lines(read_stdin_and_filter_file()); 101} elsif ($arg =~ /--i[nfo]/) { 102 my ($incs, $types, $funcs) = parse_info(filter_lines(read_stdin_and_filter_file())); 103 exit print @{$incs}, @{$types}, @{$funcs}; 104} elsif ($arg =~ /--co[mpile]/) { 105 exit compilation_screen("mock_" . shift @ARGV); 106} elsif ($arg =~ /--cle[an]/) { 107 exit system("mv $TMPDIR $TMPDIR.deleted"); 108} elsif ($arg =~ /--u[nittest]/) { 109 print(STDERR "unit testing device"); 110} 111 112sub help { 113 print <<EOF 114 Usage: 115 Specify a namespace on the command line for the shared structure data. 116 Then pipe the C file on stdin and one source and one header file will 117 be created based upon the namespace convention 118 119 mockcify.pl stack_l2cap_api < stack/l2cap/l2c_api.cc 120 121 Output files: 122 mock_stack_l2cap_api.cc 123 mock_stack_l2cap_api.h 124 125 The tool is not capable of parsing C++ and a workaround is to remove 126 C++ in the source prior to mock-C-fying the source. 127 128EOF 129} 130 131## Only single arg is taken 132my $namespace = $arg; 133 134if ($namespace =~ /^--/) { 135 print(STDERR "ERROR Halting due to ill-formed namespace expression \'$namespace\'\n"); 136 exit -1; 137} 138 139### 140### Phase 0: Prepare input and output file streams 141### 142 143## Default to stdout 144my $FH_SRC; 145my $FH_HDR; 146 147my $src_filename; 148my $hdr_filename; 149## If namepace specified then write to that source and header 150if ($namespace eq "TESTING") { 151 $FH_SRC = *STDOUT; 152 $FH_HDR = *STDOUT; 153} else { 154 $src_filename="mock_" . $namespace . ".cc"; 155 $hdr_filename="mock_" . $namespace . ".h"; 156 157 open($FH_SRC, ">", $OUTDIR .$src_filename) 158 or die $!; 159 160 open($FH_HDR, ">", $OUTDIR .$hdr_filename) 161 or die $!; 162} 163 164### 165### Phase 1: Read input file and apply single line filtering 166### 167my $text = read_stdin_and_filter_file(); 168 169### 170### Phase 2: Apply Multiline filters 171### 172$text = filter_lines($text); 173 174## 175## Phase 3: Extract required mock information 176## 177my ($includes_ref, $typedefs_ref, $functions_ref, $usings_ref, $namespaces_ref) = parse_info($text); 178my @includes = @{$includes_ref}; 179my @typedefs = @{$typedefs_ref}; 180my @functions = @{$functions_ref}; 181my @namespaces = @{$namespaces_ref}; 182my @usings = @{$usings_ref}; 183 184@includes = reject_include_list(@includes); 185 186@functions = grep { parse_function_into_components ($_) } @functions; 187 188## 189## Phase 4: Output the mocks source and header 190## 191print_source($FH_SRC); 192print_header($FH_HDR); 193 194close ($FH_SRC); 195close ($FH_HDR); 196 197## Format the final source code files 198if (defined $src_filename) { 199 system("clang-format", "-i", $OUTDIR . $src_filename); 200 system("clang-format", "-i", $OUTDIR . $hdr_filename); 201} 202 203print(STDERR "Generated files:", $OUTDIR . $src_filename, " ", $OUTDIR . $hdr_filename, "\n"); 204 205if ($COMPILE_SCREEN_ENABLED) { 206 my $rc = compilation_screen("mock_" . $namespace); 207 exit ($rc == 256) ?1 : 0; 208} 209 210sub reject_include_list { 211 my @incs = (); 212 foreach (@_) { 213 push(@incs, $_); 214 } 215 return @incs; 216} 217 218sub compile_screen_failed { 219 my $src = shift @_; 220 print STDERR <<EOF 221 MOCK Compilation is EXPERIMENTAL ONLY 222 223 ERROR Failed to compile \'$src\' NOTE: This does not mean 224 the mock is unusable as the tool only screens the compilation. 225 226 There could be one of 3 problems: 227 1. Undeclared external surface or dependency 228 2. C++ code or namespaces mixed in with C code 229 3. An issue with proper mock'ing with mockcify. 230EOF 231} 232 233sub compilation_screen { 234 my $base= shift @_; 235 my $src=$base . ".cc"; 236 my $hdr=$base . ".h"; 237 238 ## Verious external or generated header not needed for mocks 239 foreach(( 240 "test/mock/mock.h", 241 "src/message_loop_thread.rs.h", 242 "android/hardware/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.h", 243 "android/hardware/bluetooth/audio/2.2/types.h", 244 )) { 245 system("mkdir -p $INCDIR". dirname($_)); 246 system("touch $INCDIR/$_"); 247 } 248 my @incs = ( 249 $INCDIR, 250 $LIBCHROME, 251 ".", 252 "audio_hal_interface/", 253 "include/", 254 "stack/include/", 255 "btif/include/", 256 "internal_include", 257 "osi/include/", 258 "test/mock/", 259 "types/", 260 ); 261 ## Any additional compiler definitions that may be required 262 my @compiler_defs = ( 263 ); 264 265 my $link="test/mock/$hdr"; 266 unlink "$INCDIR/$link"; 267 symlink "$OUTDIR/$hdr", "$INCDIR/$link"; 268 system("$CC -c -std=c++20 -o /dev/null -D" . join(" -D", @compiler_defs) . " -I" . join(" -I", @incs) . " $OUTDIR/$src"); 269 my $rc = $?; 270 ($? == 0) 271 ? printf(STDERR "SUCCESS Compiled unit \'$src\'\n") 272 : compile_screen_failed($src); 273 return $rc; 274} 275 276### 277### Phase 4.1: Print the source compilation unit and the associated structues 278### 279sub print_source { 280 my $FH = shift @_; 281 print_copyright($FH); 282 print_generated_note($FH); 283 284 print_mock_header_include($FH); 285 print_mock_decl_src($FH); 286 print_usings($FH); 287 print_internal_structs($FH); 288 print_source_namespace_structs($FH); 289 print_static_return_values($FH); 290 print_mocked_functions($FH); 291 292 print $FH "// END mockcify generation\n"; 293} 294 295### 296### Phase 4.2 Print the header unit to be included with the test 297### 298sub print_header { 299 my $FH = shift @_; 300 print_copyright($FH); 301 print_pragma($FH); 302 print_generated_note($FH); 303 print_mock_decl_hdr($FH); 304 305 print_includes($FH); 306 print_usings($FH); 307 print_defs($FH); 308 print_header_test_mock_namespace_structs($FH); 309 print $FH "// END mockcify generation"; 310} 311 312sub get_function_param_names { 313 my $name = shift @_; 314 my @param_names; 315 foreach (0..$#{$function_param_names{$name}}) { 316 my $param_name = $function_param_names{$name}[$_]; 317 my $param_type = $function_param_types{$name}[$_]; 318 319 if (!defined($param_type)) { 320 printf(STDERR "Unable to find param type def for $name\n"); 321 next; 322 } 323 if ($param_type =~ /unique_ptr/) { 324 ## Wrap name in a move operation 325 push(@param_names, "std::move($param_name)"); 326 } else { 327 push(@param_names, $param_name); 328 } 329 } 330 return join(',', @param_names); 331} 332 333## 334## Parse a function signature into 4 basic components and insert into 335## the global hashes and arrays. 336## 1. @function return type 337## 2. @function name 338## 3. %param types 339## 4. %param names 340## 341sub parse_function_into_components { 342 my $function = shift @_; 343 ## Ensure this is really a function string 344 assert(substr $function, -1 eq ')'); 345 346 ## Split on first occurrence of open paren to get return 347 ## type and name of function 348 my ($return_type_and_name, $params) = split '\(', $function, 2; 349 if (!defined($params)) { 350 printf(STDERR "WARNING \'params\' is undefined \"$params\" function:\'$function\'\n"); 351 return 0; 352 } 353 ## Remove input params closing paren 354 $params=~ s/\).*$//; 355 356 ## Parse the return type and function name 357 my ($return_type, $name) = $return_type_and_name =~ /(.*)\s(.*)/; 358 359 if (!defined($name)) { 360 printf(STDERR "WARNING \'name\' is undefined \"$return_type_and_name\" a [con|des]tructor ?\n"); 361 return 0; 362 } 363 if ($name =~ /::/) { 364 printf(STDERR "WARNING \'name\' is unhandled class method \'$name\'\n"); 365 return 0; 366 } 367 368 ## Store away complete function signature 369 $function_signature{$name} = $function; 370 371 ## Store away the parameter type and names 372 chomp($params); 373 $function_params{$name} = $params; 374 375 ## Parse the parameter types and names 376 my @param_types; 377 my @param_names; 378 379 ## Skip when void keyword used for no parameters 380 if ($params ne "void") { 381 ## TODO Replace all comma types within angle brackets before split 382 foreach (split ',', $params) { 383 s/^\s+//; 384 if (/\(/) { 385 ## TODO Parameter is a C style function 386 my @vars; 387 my @f = split /[\(\)]/; 388 push(@vars, substr $f[1], 1); 389 } else { 390 ## Store the type and name 391 my ($type, $name) = /(.*)\s(.*)/; 392 push(@param_names, $name); 393 push(@param_types, $type); 394 } 395 } 396 } 397 push(@function_names, $name); 398 $function_return_types{$name} = $return_type; 399 $function_param_types{$name} = \@param_types; 400 $function_param_names{$name} = \@param_names; 401 return 1; 402} 403 404## 405## Read a file from stdin and does a first pass simple 406## filtering that removes single lines. 407## 408sub read_stdin_and_filter_file { 409 my @filtered_lines; 410 my @clang_format=clang_format(); 411 foreach (@clang_format) { 412 ## Update header guards with compiler #pragma for proper 413 ## decision processing of header or source 414 s/^#ifndef [A-Z_0-9]+_H/#pragma once/; 415 416 unless (/^extern/ 417 or /^#define / 418 or / = \{/ 419 or /^#if / 420 or /^constexpr/ 421 or /^#ifdef/ 422 or /^#ifndef/ 423 or /^#else/ 424 or /^enum/ 425 or /^static.*;$/ 426 or /^#endif/) { 427 ## Remove any single line C style comments 428 s:/\*.*\*/::; 429 push(@filtered_lines, $_); 430 } 431 } 432 return join('', @filtered_lines); 433} 434 435sub filter_lines { 436 $_ = shift @_; 437 ## Remove anonymous namespaces 438 ## $text =~ s/namespace \{.*\n\} \/\/ namespace/\n/sg; 439 s/namespace \{.*\n\} \/\/ namespace?/\n/sg; 440 s/namespace \{.?\n\}/\n/g; 441 ## Remove C style comments 442 s/\s*\/\*(?:(?!\*\/).)*\*\/\n?/\n/sg; 443 ## Remove Cpp style comments 444 s/\s*\/\/.*//g; 445 ## Remove unnecessary bluetooth osi specific modifier 446 s/UNUSED_ATTR//g; 447 ## Modify internally defined structure typedefs 448 s/typedef struct \{.*?\n\} (\w+);/typedef struct $MOCKCIFY_BRACKET_GROUP $1;/sg; 449 ## Modify internally defined structure typedefs 450 s/typedef struct (\w+) \{.*?\n\} (\w+);/struct $1 $MOCKCIFY_BRACKET_GROUP;/sg; 451 ## Modify internally defined structures 452 s/struct (\w+) \{.*?\n\};/struct $1 $MOCKCIFY_BRACKET_GROUP;/sg; 453 ## Remove lines only with spaces 454 s/^\s+$//sg; 455 return $_; 456} 457 458sub parse_info { 459 if (/\n#pragma once\n/) { 460 return parse_info_header(shift @_); 461 } else { 462 return parse_info_source(shift @_); 463 } 464} 465 466sub parse_info_header { 467 my (@includes, @typedefs, @functions, @usings, @namespaces); 468 foreach (split('\n')) { 469 chomp(); 470 if (/^ /) { 471 } elsif (/^#include /) { 472 push(@includes, $_); 473 } elsif (/^typedef /) { 474 push @typedefs, $_; 475 } elsif ($_ =~ /^ *$/) { 476 # Skip function body indicated by indentation 477 } elsif ($_ =~ /^}/) { 478 # Skip function curly bracket closure 479 } elsif (/^namespace/) { 480 push @namespaces, $_; 481 } elsif (/\(/) { 482 # Add function signature 483 chomp(); 484 ## Remove all function body after signature 485 s/{.*$//; 486 ## Remove whitespace on both ends 487 s/^\s+|\s+$//g; 488 ## Ignore locally linked functions 489 next if (/^static/); 490 ## Reduce all remaining whitespace to a single space 491 s/\s+/ /g; 492 ## Remove any semi colons 493 s/;//g; 494 push(@functions, "$_\n"); 495 } else { 496 # Not a function. skip 497 } 498 } 499 printf(STDERR "Parsed HEADER lines includes:%d typedefs:%d functions:%d\n", 500 scalar(@includes), scalar(@typedefs), scalar(@functions)); 501 return (\@includes, \@typedefs, \@functions, \@usings, \@namespaces); 502} 503 504sub parse_info_source{ 505 my @s = split('\n', $_); 506 my (@includes, @typedefs, @functions, @usings, @namespaces); 507 foreach (@s) { 508 chomp(); 509 if (/^ /) { 510 } elsif (/^#include /) { 511 push @includes, $_; 512 } elsif (/^typedef /) { 513 push @typedefs, $_; 514 } elsif (/^using /) { 515 push @usings, $_; 516 } elsif (/^namespace/) { 517 push @namespaces, $_; 518 } elsif ($_ =~ /^ *$/) { 519 # Skip function body indicated by indentation 520 } elsif ($_ =~ /^}/) { 521 # Skip function curly bracket closure 522 } elsif (/\{/) { 523 # Add function signature 524 chomp(); 525 ## Remove all function body after signature 526 s/{.*$//; 527 ## Remove whitespace on both ends 528 s/^\s+|\s+$//g; 529 ## Ignore locally linked functions 530 next if (/^static/); 531 ## Reduce all remaining whitespace to a single space 532 s/\s+/ /g; 533 push(@functions, "$_\n"); 534 } else { 535 # Not a function. skip 536 } 537 } 538 printf(STDERR "Parsed SOURCE lines includes:%d typedefs:%d functions:%d\n", 539 scalar(@includes), scalar(@typedefs), scalar(@functions)); 540 return (\@includes, \@typedefs, \@functions, \@usings, \@namespaces); 541} 542 543## Returns the default type specified by the function return type. 544## These are processed in priority order. 545sub get_default_return_value_from_type { 546 $_ = shift @_; 547 assert($_ ne ''); 548 if (/^bool/) { 549 return "false"; 550 } elsif (/\*$/ or /^std::unique_ptr/ or /^std::shared_ptr/) { ## Pointer return val 551 return "nullptr"; 552 } elsif (/^void/) { 553 return ""; 554 } elsif (/^std::string/) { 555 return "std::string()"; 556 } elsif (/^std::list\<entry_t\>::iterator/) { 557 return "static std::list<entry_t> v"; 558 } elsif (/^std::list\<section_t\>::iterator/) { 559 return "std::list<section_t>"; 560 } elsif (/reactor_status_t/) { 561 return "REACTOR_STATUS_DONE"; 562 } elsif (/tL2CAP_LE_RESULT_CODE/) { 563 return "L2CAP_LE_RESULT_CONN_OK"; 564 } elsif (/std::vector/) { 565 return "retval"; 566 } elsif (/tBT_TRANSPORT/) { 567 return "BT_TRANSPORT_BR_EDR"; 568 } elsif (/tSDP_STATUS/) { 569 return "SDP_SUCCESS"; 570 } elsif (/tGATT_STATUS/) { 571 return "GATT_SUCCESS"; 572 } elsif (/tHID_STATUS/) { 573 return "HID_SUCCESS"; 574 } elsif (/future_t\*/) { 575 return "FUTURE_FAIL"; 576 } elsif(/bt_status_t/) { 577 return "BT_STATUS_SUCCESS"; 578 } elsif(/.*module_t\*/) { 579 return "nullptr"; 580 } elsif(/btav_a2dp_codec_index_t/) { 581 return "BTAV_A2DP_CODEC_INDEX_SOURCE_MIN"; 582 } elsif(/tBTA_SDP_STATUS/) { 583 return "BTA_SDP_SUCCESS"; 584 } elsif(/tBTA_STATUS/) { 585 return "BTA_SUCCESS"; 586 } elsif(/tBTA_JV_STATUS/) { 587 return "tBTA_JV_STATUS::SUCCESS"; 588 } else { 589 ## Decay to int type 590 return "0"; 591 } 592} 593 594## 595## Various print output boilerplate 596### 597sub print_copyright { 598 my $FH = shift @_; 599print $FH <<EOF 600/* 601 * Copyright $YEAR The Android Open Source Project 602 * 603 * Licensed under the Apache License, Version 2.0 (the "License"); 604 * you may not use this file except in compliance with the License. 605 * You may obtain a copy of the License at 606 * 607 * http://www.apache.org/licenses/LICENSE-2.0 608 * 609 * Unless required by applicable law or agreed to in writing, software 610 * distributed under the License is distributed on an "AS IS" BASIS, 611 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 612 * See the License for the specific language governing permissions and 613 * limitations under the License. 614 */ 615EOF 616} 617 618## Print body of each function 619sub print_mocked_functions { 620 my $FH = shift @_; 621 print $FH <<EOF; 622// Mocked functions, if any 623EOF 624 foreach my $name (sort @function_names) { 625 my $return_type = $function_return_types{$name}; 626 assert($return_type ne ''); 627 628 my $return_keyword = $return_type eq "void" ? "" : "return"; 629 my $function_param_names = get_function_param_names($name); 630 631 print $FH <<EOF; 632$function_signature{$name} { 633 inc_func_call_count(__func__); 634 ${return_keyword} test::mock::${namespace}::${name}($function_param_names); 635} 636EOF 637 } 638 print $FH <<EOF; 639// Mocked functions complete 640EOF 641} 642 643sub print_static_return_values { 644 my $FH = shift @_; 645 print $FH <<EOF; 646// Mocked function return values, if any 647namespace test { 648namespace mock { 649namespace $namespace { 650 651EOF 652 foreach my $name (sort @function_names) { 653 $name =~ s/\s+$//; 654 my $return_type = $function_return_types{$name}; 655 assert($return_type ne ''); 656 657 next if ($return_type eq "void"); 658 my $default_return_value = get_default_return_value_from_type($return_type); 659 print $FH "${return_type} ${name}::return_value = ${default_return_value};\n"; 660 } 661 print $FH <<EOF; 662 663} // namespace $namespace 664} // namespace mock 665} // namespace test 666 667EOF 668} 669 670## 671## Collection of mocked functions 672sub print_source_namespace_structs { 673 my $FH = shift @_; 674 print $FH <<EOF; 675namespace test { 676namespace mock { 677namespace $namespace { 678 679// Function state capture and return values, if needed 680EOF 681 foreach my $name (sort @function_names) { 682 print $FH "struct $name $name;\n"; 683 } 684 print $FH <<EOF; 685 686} // namespace $namespace 687} // namespace mock 688} // namespace test 689 690EOF 691} 692 693## 694## Print the definitions of the various structures for the header files 695## 696sub print_header_test_mock_namespace_structs { 697 my $FH = shift @_; 698 print $FH <<EOF; 699namespace test { 700namespace mock { 701namespace $namespace { 702 703// Shared state between mocked functions and tests 704EOF 705 foreach my $name (sort @function_names) { 706 my $input_params = $function_params{$name}; 707 my $vars_commented_out_input_params = comment_out_input_vars($input_params); 708 my $return_type = $function_return_types{$name}; 709 my @param_names = $function_param_names{$name}; 710 assert($return_type ne ''); 711 712 my $function_param_names = get_function_param_names($name); 713 my $return_keyword = $return_type eq "void" ? "" : "return"; 714 my $return_statement = $return_type eq "void" ? "" : "return return_value;"; 715 my $return_definition = $return_type eq "void" ? "" : "static $return_type return_value;"; 716 717print $FH <<EOF; 718// Name: $name 719// Params: $input_params 720// Return: $return_type 721struct $name { 722EOF 723 if ($return_definition ne "") { 724 print $FH "$return_definition\n"; 725 } 726print $FH <<EOF; 727 std::function<$return_type($input_params)> body{[]($vars_commented_out_input_params){$return_statement}}; 728 $return_type operator()($input_params) { ${return_keyword} body($function_param_names);}; 729}; 730extern struct $name $name; 731 732EOF 733 } 734print $FH <<EOF; 735} // namespace $namespace 736} // namespace mock 737} // namespace test 738 739EOF 740} 741 742sub print_pragma { 743 my $FH = shift @_; 744print $FH <<EOF 745#pragma once 746 747EOF 748} 749 750sub print_generated_note { 751 my $FH = shift @_; 752 my $gen = scalar(@functions); 753print $FH <<EOF; 754/* 755 * Generated mock file from original source file 756 * Functions generated:$gen 757 * 758 * mockcify.pl ver $VERSION 759 */ 760 761EOF 762} 763 764sub print_usings { 765 my $FH = shift @_; 766print $FH <<EOF; 767// Original usings 768EOF 769 foreach (sort @usings) { 770 print $FH $_, "\n"; 771 } 772 print($FH "\n");; 773} 774 775sub print_includes { 776 my $FH = shift @_; 777 print $FH <<EOF; 778// Original included files, if any 779// NOTE: Since this is a mock file with mock definitions some number of 780// include files may not be required. The include-what-you-use 781// still applies, but crafting proper inclusion is out of scope 782// for this effort. This compilation unit may compile as-is, or 783// may need attention to prune from (or add to ) the inclusion set. 784EOF 785 foreach (sort @includes) { 786 print $FH $_, "\n"; 787 } 788 print($FH "\n");; 789} 790 791sub print_mock_header_include { 792 my $FH = shift @_; 793 print $FH <<EOF; 794// Mock include file to share data between tests and mock 795#include "test/mock/mock_${namespace}.h" 796 797EOF 798} 799 800sub print_mock_decl_hdr { 801 my $FH = shift @_; 802print $FH <<EOF; 803#include <cstdint> 804#include <functional> 805 806EOF 807} 808 809sub print_mock_decl_src { 810 my $FH = shift @_; 811print $FH <<EOF; 812#include <cstdint> 813 814#include "test/common/mock_functions.h" 815 816EOF 817} 818 819sub print_defs { 820 my $FH = shift @_; 821 print $FH <<EOF; 822// Mocked compile conditionals, if any 823 824EOF 825} 826 827sub print_internal_structs { 828 my $FH = shift @_; 829 print $FH <<EOF; 830// Mocked internal structures, if any 831EOF 832 833 foreach (sort @structs) { 834 print $FH $_,"\n"}; 835 print $FH "\n"; 836} 837 838sub assert { 839 my ($condition, $msg) = @_; 840 return if $condition; 841 if (!$msg) { 842 my ($pkg, $file, $line) = caller(0); 843 open my $fh, "<", $file; 844 my @lines = <$fh>; 845 close $fh; 846 $msg = "$file:$line: " . $lines[$line - 1]; 847 } 848 die "Assertion failed: $msg"; 849} 850