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 next if (/init_flags/); 214 push(@incs, $_); 215 } 216 return @incs; 217} 218 219sub compile_screen_failed { 220 my $src = shift @_; 221 print STDERR <<EOF 222 MOCK Compilation is EXPERIMENTAL ONLY 223 224 ERROR Failed to compile \'$src\' NOTE: This does not mean 225 the mock is unusable as the tool only screens the compilation. 226 227 There could be one of 3 problems: 228 1. Undeclared external surface or dependency 229 2. C++ code or namespaces mixed in with C code 230 3. An issue with proper mock'ing with mockcify. 231EOF 232} 233 234sub compilation_screen { 235 my $base= shift @_; 236 my $src=$base . ".cc"; 237 my $hdr=$base . ".h"; 238 239 ## Verious external or generated header not needed for mocks 240 foreach(( 241 "test/mock/mock.h", 242 "src/init_flags.rs.h", 243 "src/message_loop_thread.rs.h", 244 "android/hardware/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.h", 245 "android/hardware/bluetooth/audio/2.2/types.h", 246 )) { 247 system("mkdir -p $INCDIR". dirname($_)); 248 system("touch $INCDIR/$_"); 249 } 250 my @incs = ( 251 $INCDIR, 252 $LIBCHROME, 253 ".", 254 "audio_hal_interface/", 255 "include/", 256 "stack/include/", 257 "btif/include/", 258 "internal_include", 259 "osi/include/", 260 "test/mock/", 261 "types/", 262 ); 263 ## Any additional compiler definitions that may be required 264 my @compiler_defs = ( 265 ); 266 267 my $link="test/mock/$hdr"; 268 unlink "$INCDIR/$link"; 269 symlink "$OUTDIR/$hdr", "$INCDIR/$link"; 270 system("$CC -c -std=c++20 -o /dev/null -D" . join(" -D", @compiler_defs) . " -I" . join(" -I", @incs) . " $OUTDIR/$src"); 271 my $rc = $?; 272 ($? == 0) 273 ? printf(STDERR "SUCCESS Compiled unit \'$src\'\n") 274 : compile_screen_failed($src); 275 return $rc; 276} 277 278### 279### Phase 4.1: Print the source compilation unit and the associated structues 280### 281sub print_source { 282 my $FH = shift @_; 283 print_copyright($FH); 284 print_generated_note($FH); 285 286 print_mock_header_include($FH); 287 print_mock_decl_src($FH); 288 print_usings($FH); 289 print_internal_structs($FH); 290 print_source_namespace_structs($FH); 291 print_static_return_values($FH); 292 print_mocked_functions($FH); 293 294 print $FH "// END mockcify generation\n"; 295} 296 297### 298### Phase 4.2 Print the header unit to be included with the test 299### 300sub print_header { 301 my $FH = shift @_; 302 print_copyright($FH); 303 print_pragma($FH); 304 print_generated_note($FH); 305 print_mock_decl_hdr($FH); 306 307 print_includes($FH); 308 print_usings($FH); 309 print_defs($FH); 310 print_header_test_mock_namespace_structs($FH); 311 print $FH "// END mockcify generation"; 312} 313 314sub get_function_param_names { 315 my $name = shift @_; 316 my @param_names; 317 foreach (0..$#{$function_param_names{$name}}) { 318 my $param_name = $function_param_names{$name}[$_]; 319 my $param_type = $function_param_types{$name}[$_]; 320 321 if (!defined($param_type)) { 322 printf(STDERR "Unable to find param type def for $name\n"); 323 next; 324 } 325 if ($param_type =~ /unique_ptr/) { 326 ## Wrap name in a move operation 327 push(@param_names, "std::move($param_name)"); 328 } else { 329 push(@param_names, $param_name); 330 } 331 } 332 return join(',', @param_names); 333} 334 335## 336## Parse a function signature into 4 basic components and insert into 337## the global hashes and arrays. 338## 1. @function return type 339## 2. @function name 340## 3. %param types 341## 4. %param names 342## 343sub parse_function_into_components { 344 my $function = shift @_; 345 ## Ensure this is really a function string 346 assert(substr $function, -1 eq ')'); 347 348 ## Split on first occurrence of open paren to get return 349 ## type and name of function 350 my ($return_type_and_name, $params) = split '\(', $function, 2; 351 if (!defined($params)) { 352 printf(STDERR "WARNING \'params\' is undefined \"$params\" function:\'$function\'\n"); 353 return 0; 354 } 355 ## Remove input params closing paren 356 $params=~ s/\).*$//; 357 358 ## Parse the return type and function name 359 my ($return_type, $name) = $return_type_and_name =~ /(.*)\s(.*)/; 360 361 if (!defined($name)) { 362 printf(STDERR "WARNING \'name\' is undefined \"$return_type_and_name\" a [con|des]tructor ?\n"); 363 return 0; 364 } 365 if ($name =~ /::/) { 366 printf(STDERR "WARNING \'name\' is unhandled class method \'$name\'\n"); 367 return 0; 368 } 369 370 ## Store away complete function signature 371 $function_signature{$name} = $function; 372 373 ## Store away the parameter type and names 374 chomp($params); 375 $function_params{$name} = $params; 376 377 ## Parse the parameter types and names 378 my @param_types; 379 my @param_names; 380 381 ## Skip when void keyword used for no parameters 382 if ($params ne "void") { 383 ## TODO Replace all comma types within angle brackets before split 384 foreach (split ',', $params) { 385 s/^\s+//; 386 if (/\(/) { 387 ## TODO Parameter is a C style function 388 my @vars; 389 my @f = split /[\(\)]/; 390 push(@vars, substr $f[1], 1); 391 } else { 392 ## Store the type and name 393 my ($type, $name) = /(.*)\s(.*)/; 394 push(@param_names, $name); 395 push(@param_types, $type); 396 } 397 } 398 } 399 push(@function_names, $name); 400 $function_return_types{$name} = $return_type; 401 $function_param_types{$name} = \@param_types; 402 $function_param_names{$name} = \@param_names; 403 return 1; 404} 405 406## 407## Read a file from stdin and does a first pass simple 408## filtering that removes single lines. 409## 410sub read_stdin_and_filter_file { 411 my @filtered_lines; 412 my @clang_format=clang_format(); 413 foreach (@clang_format) { 414 ## Update header guards with compiler #pragma for proper 415 ## decision processing of header or source 416 s/^#ifndef [A-Z_0-9]+_H/#pragma once/; 417 418 unless (/^extern/ 419 or /^#define / 420 or / = \{/ 421 or /^#if / 422 or /^constexpr/ 423 or /^#ifdef/ 424 or /^#ifndef/ 425 or /^#else/ 426 or /^enum/ 427 or /^static.*;$/ 428 or /^#endif/) { 429 ## Remove any single line C style comments 430 s:/\*.*\*/::; 431 push(@filtered_lines, $_); 432 } 433 } 434 return join('', @filtered_lines); 435} 436 437sub filter_lines { 438 $_ = shift @_; 439 ## Remove anonymous namespaces 440 ## $text =~ s/namespace \{.*\n\} \/\/ namespace/\n/sg; 441 s/namespace \{.*\n\} \/\/ namespace?/\n/sg; 442 s/namespace \{.?\n\}/\n/g; 443 ## Remove C style comments 444 s/\s*\/\*(?:(?!\*\/).)*\*\/\n?/\n/sg; 445 ## Remove Cpp style comments 446 s/\s*\/\/.*//g; 447 ## Remove unnecessary bluetooth osi specific modifier 448 s/UNUSED_ATTR//g; 449 ## Modify internally defined structure typedefs 450 s/typedef struct \{.*?\n\} (\w+);/typedef struct $MOCKCIFY_BRACKET_GROUP $1;/sg; 451 ## Modify internally defined structure typedefs 452 s/typedef struct (\w+) \{.*?\n\} (\w+);/struct $1 $MOCKCIFY_BRACKET_GROUP;/sg; 453 ## Modify internally defined structures 454 s/struct (\w+) \{.*?\n\};/struct $1 $MOCKCIFY_BRACKET_GROUP;/sg; 455 ## Remove lines only with spaces 456 s/^\s+$//sg; 457 return $_; 458} 459 460sub parse_info { 461 if (/\n#pragma once\n/) { 462 return parse_info_header(shift @_); 463 } else { 464 return parse_info_source(shift @_); 465 } 466} 467 468sub parse_info_header { 469 my (@includes, @typedefs, @functions, @usings, @namespaces); 470 foreach (split('\n')) { 471 chomp(); 472 if (/^ /) { 473 } elsif (/^#include /) { 474 push(@includes, $_); 475 } elsif (/^typedef /) { 476 push @typedefs, $_; 477 } elsif ($_ =~ /^ *$/) { 478 # Skip function body indicated by indentation 479 } elsif ($_ =~ /^}/) { 480 # Skip function curly bracket closure 481 } elsif (/^namespace/) { 482 push @namespaces, $_; 483 } elsif (/\(/) { 484 # Add function signature 485 chomp(); 486 ## Remove all function body after signature 487 s/{.*$//; 488 ## Remove whitespace on both ends 489 s/^\s+|\s+$//g; 490 ## Ignore locally linked functions 491 next if (/^static/); 492 ## Reduce all remaining whitespace to a single space 493 s/\s+/ /g; 494 ## Remove any semi colons 495 s/;//g; 496 push(@functions, "$_\n"); 497 } else { 498 # Not a function. skip 499 } 500 } 501 printf(STDERR "Parsed HEADER lines includes:%d typedefs:%d functions:%d\n", 502 scalar(@includes), scalar(@typedefs), scalar(@functions)); 503 return (\@includes, \@typedefs, \@functions, \@usings, \@namespaces); 504} 505 506sub parse_info_source{ 507 my @s = split('\n', $_); 508 my (@includes, @typedefs, @functions, @usings, @namespaces); 509 foreach (@s) { 510 chomp(); 511 if (/^ /) { 512 } elsif (/^#include /) { 513 push @includes, $_; 514 } elsif (/^typedef /) { 515 push @typedefs, $_; 516 } elsif (/^using /) { 517 push @usings, $_; 518 } elsif (/^namespace/) { 519 push @namespaces, $_; 520 } elsif ($_ =~ /^ *$/) { 521 # Skip function body indicated by indentation 522 } elsif ($_ =~ /^}/) { 523 # Skip function curly bracket closure 524 } elsif (/\{/) { 525 # Add function signature 526 chomp(); 527 ## Remove all function body after signature 528 s/{.*$//; 529 ## Remove whitespace on both ends 530 s/^\s+|\s+$//g; 531 ## Ignore locally linked functions 532 next if (/^static/); 533 ## Reduce all remaining whitespace to a single space 534 s/\s+/ /g; 535 push(@functions, "$_\n"); 536 } else { 537 # Not a function. skip 538 } 539 } 540 printf(STDERR "Parsed SOURCE lines includes:%d typedefs:%d functions:%d\n", 541 scalar(@includes), scalar(@typedefs), scalar(@functions)); 542 return (\@includes, \@typedefs, \@functions, \@usings, \@namespaces); 543} 544 545## Returns the default type specified by the function return type. 546## These are processed in priority order. 547sub get_default_return_value_from_type { 548 $_ = shift @_; 549 assert($_ ne ''); 550 if (/^bool/) { 551 return "false"; 552 } elsif (/\*$/ or /^std::unique_ptr/ or /^std::shared_ptr/) { ## Pointer return val 553 return "nullptr"; 554 } elsif (/^void/) { 555 return ""; 556 } elsif (/^std::string/) { 557 return "std::string()"; 558 } elsif (/^std::list\<entry_t\>::iterator/) { 559 return "static std::list<entry_t> v"; 560 } elsif (/^std::list\<section_t\>::iterator/) { 561 return "std::list<section_t>"; 562 } elsif (/reactor_status_t/) { 563 return "REACTOR_STATUS_DONE"; 564 } elsif (/tL2CAP_LE_RESULT_CODE/) { 565 return "L2CAP_LE_RESULT_CONN_OK"; 566 } elsif (/std::vector/) { 567 return "retval"; 568 } elsif (/tBT_TRANSPORT/) { 569 return "BT_TRANSPORT_BR_EDR"; 570 } elsif (/tSDP_STATUS/) { 571 return "SDP_SUCCESS"; 572 } elsif (/tGATT_STATUS/) { 573 return "GATT_SUCCESS"; 574 } elsif (/tHID_STATUS/) { 575 return "HID_SUCCESS"; 576 } elsif (/future_t\*/) { 577 return "FUTURE_FAIL"; 578 } elsif(/bt_status_t/) { 579 return "BT_STATUS_SUCCESS"; 580 } elsif(/.*module_t\*/) { 581 return "nullptr"; 582 } elsif(/btav_a2dp_codec_index_t/) { 583 return "BTAV_A2DP_CODEC_INDEX_SOURCE_MIN"; 584 } elsif(/tBTA_SDP_STATUS/) { 585 return "BTA_SDP_SUCCESS"; 586 } elsif(/tBTA_STATUS/) { 587 return "BTA_SUCCESS"; 588 } elsif(/tBTA_JV_STATUS/) { 589 return "tBTA_JV_STATUS::SUCCESS"; 590 } else { 591 ## Decay to int type 592 return "0"; 593 } 594} 595 596## 597## Various print output boilerplate 598### 599sub print_copyright { 600 my $FH = shift @_; 601print $FH <<EOF 602/* 603 * Copyright $YEAR The Android Open Source Project 604 * 605 * Licensed under the Apache License, Version 2.0 (the "License"); 606 * you may not use this file except in compliance with the License. 607 * You may obtain a copy of the License at 608 * 609 * http://www.apache.org/licenses/LICENSE-2.0 610 * 611 * Unless required by applicable law or agreed to in writing, software 612 * distributed under the License is distributed on an "AS IS" BASIS, 613 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 614 * See the License for the specific language governing permissions and 615 * limitations under the License. 616 */ 617EOF 618} 619 620## Print body of each function 621sub print_mocked_functions { 622 my $FH = shift @_; 623 print $FH <<EOF; 624// Mocked functions, if any 625EOF 626 foreach my $name (sort @function_names) { 627 my $return_type = $function_return_types{$name}; 628 assert($return_type ne ''); 629 630 my $return_keyword = $return_type eq "void" ? "" : "return"; 631 my $function_param_names = get_function_param_names($name); 632 633 print $FH <<EOF; 634$function_signature{$name} { 635 inc_func_call_count(__func__); 636 ${return_keyword} test::mock::${namespace}::${name}($function_param_names); 637} 638EOF 639 } 640 print $FH <<EOF; 641// Mocked functions complete 642EOF 643} 644 645sub print_static_return_values { 646 my $FH = shift @_; 647 print $FH <<EOF; 648// Mocked function return values, if any 649namespace test { 650namespace mock { 651namespace $namespace { 652 653EOF 654 foreach my $name (sort @function_names) { 655 $name =~ s/\s+$//; 656 my $return_type = $function_return_types{$name}; 657 assert($return_type ne ''); 658 659 next if ($return_type eq "void"); 660 my $default_return_value = get_default_return_value_from_type($return_type); 661 print $FH "${return_type} ${name}::return_value = ${default_return_value};\n"; 662 } 663 print $FH <<EOF; 664 665} // namespace $namespace 666} // namespace mock 667} // namespace test 668 669EOF 670} 671 672## 673## Collection of mocked functions 674sub print_source_namespace_structs { 675 my $FH = shift @_; 676 print $FH <<EOF; 677namespace test { 678namespace mock { 679namespace $namespace { 680 681// Function state capture and return values, if needed 682EOF 683 foreach my $name (sort @function_names) { 684 print $FH "struct $name $name;\n"; 685 } 686 print $FH <<EOF; 687 688} // namespace $namespace 689} // namespace mock 690} // namespace test 691 692EOF 693} 694 695## 696## Print the definitions of the various structures for the header files 697## 698sub print_header_test_mock_namespace_structs { 699 my $FH = shift @_; 700 print $FH <<EOF; 701namespace test { 702namespace mock { 703namespace $namespace { 704 705// Shared state between mocked functions and tests 706EOF 707 foreach my $name (sort @function_names) { 708 my $input_params = $function_params{$name}; 709 my $vars_commented_out_input_params = comment_out_input_vars($input_params); 710 my $return_type = $function_return_types{$name}; 711 my @param_names = $function_param_names{$name}; 712 assert($return_type ne ''); 713 714 my $function_param_names = get_function_param_names($name); 715 my $return_keyword = $return_type eq "void" ? "" : "return"; 716 my $return_statement = $return_type eq "void" ? "" : "return return_value;"; 717 my $return_definition = $return_type eq "void" ? "" : "static $return_type return_value;"; 718 719print $FH <<EOF; 720// Name: $name 721// Params: $input_params 722// Return: $return_type 723struct $name { 724EOF 725 if ($return_definition ne "") { 726 print $FH "$return_definition\n"; 727 } 728print $FH <<EOF; 729 std::function<$return_type($input_params)> body{[]($vars_commented_out_input_params){$return_statement}}; 730 $return_type operator()($input_params) { ${return_keyword} body($function_param_names);}; 731}; 732extern struct $name $name; 733 734EOF 735 } 736print $FH <<EOF; 737} // namespace $namespace 738} // namespace mock 739} // namespace test 740 741EOF 742} 743 744sub print_pragma { 745 my $FH = shift @_; 746print $FH <<EOF 747#pragma once 748 749EOF 750} 751 752sub print_generated_note { 753 my $FH = shift @_; 754 my $gen = scalar(@functions); 755print $FH <<EOF; 756/* 757 * Generated mock file from original source file 758 * Functions generated:$gen 759 * 760 * mockcify.pl ver $VERSION 761 */ 762 763EOF 764} 765 766sub print_usings { 767 my $FH = shift @_; 768print $FH <<EOF; 769// Original usings 770EOF 771 foreach (sort @usings) { 772 print $FH $_, "\n"; 773 } 774 print($FH "\n");; 775} 776 777sub print_includes { 778 my $FH = shift @_; 779 print $FH <<EOF; 780// Original included files, if any 781// NOTE: Since this is a mock file with mock definitions some number of 782// include files may not be required. The include-what-you-use 783// still applies, but crafting proper inclusion is out of scope 784// for this effort. This compilation unit may compile as-is, or 785// may need attention to prune from (or add to ) the inclusion set. 786EOF 787 foreach (sort @includes) { 788 print $FH $_, "\n"; 789 } 790 print($FH "\n");; 791} 792 793sub print_mock_header_include { 794 my $FH = shift @_; 795 print $FH <<EOF; 796// Mock include file to share data between tests and mock 797#include "test/mock/mock_${namespace}.h" 798 799EOF 800} 801 802sub print_mock_decl_hdr { 803 my $FH = shift @_; 804print $FH <<EOF; 805#include <cstdint> 806#include <functional> 807 808EOF 809} 810 811sub print_mock_decl_src { 812 my $FH = shift @_; 813print $FH <<EOF; 814#include <cstdint> 815 816#include "test/common/mock_functions.h" 817 818EOF 819} 820 821sub print_defs { 822 my $FH = shift @_; 823 print $FH <<EOF; 824// Mocked compile conditionals, if any 825 826EOF 827} 828 829sub print_internal_structs { 830 my $FH = shift @_; 831 print $FH <<EOF; 832// Mocked internal structures, if any 833EOF 834 835 foreach (sort @structs) { 836 print $FH $_,"\n"}; 837 print $FH "\n"; 838} 839 840sub assert { 841 my ($condition, $msg) = @_; 842 return if $condition; 843 if (!$msg) { 844 my ($pkg, $file, $line) = caller(0); 845 open my $fh, "<", $file; 846 my @lines = <$fh>; 847 close $fh; 848 $msg = "$file:$line: " . $lines[$line - 1]; 849 } 850 die "Assertion failed: $msg"; 851} 852