#! /usr/bin/perl ## ## Copyright 2019 The Android Open Source Project ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. ## You may obtain a copy of the License at ## ## http://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, software ## distributed under the License is distributed on an "AS IS" BASIS, ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## See the License for the specific language governing permissions and ## limitations under the License. use File::Basename; ## mockcify version ## ## 0.7.1 Add tBTA_JV_STATUS return value ## Remove unused compiler definition HAS_NO_BDROID_BUILDCFG ## ## 0.7.0 Comment out unused mock variables ## ## 0.6.3 Streamline inclusion for headers and source ## ## 0.6.2 Add tBTA_STATUS default value, Cpp type failure log ## ## 0.6.1 Add tBTA_SDP_STATUS default value ## ## 0.6.0 Replace `extern` with `include` for mock_function_count_map ## ## 0.5.0 Add compilation check ## ## 0.4.0 Second re-write ## ## 0.3.2 Remove pragma from source file ## ## 0.3.1 Statically link return value to prevent 'this' pointer in function ## ## 0.3.0 Re-write parser. ## ## 0.2.1 Compilation units only include types and a single related header file ## Alphabetically sort functions by return value ## Add non-primative return data values in structure ## ## 0.2.0 First version ## my $VERSION = "0.7.1"; use diagnostics; use strict; use warnings; use lib "$ENV{ANDROID_BUILD_TOP}/packages/modules/Bluetooth/system/test/tool"; require 'mockcify_util.pl'; my $YEAR = "2023"; my $TOKEN = "MOCKCIFY_TOKEN"; my $MOCKCIFY_BRACKET_GROUP = "MOCKCIFY_BRACKET_GROUP"; my $CLANG_FORMAT = "/usr/bin/clang-format-13"; my $CC = "g++"; my $LIBCHROME = "../../../../external/libchrome/"; my $COMPILE_SCREEN_ENABLED = 0; my @structs; my %function_signature; my %function_return_types; my @function_names; my %function_params; my %function_param_names; my %function_param_types; sub clang_format { return `$CLANG_FORMAT --style="{ColumnLimit: 10000, PointerAlignment: Left, PointerBindsToType: true, FixNamespaceComments: true }"`; } ## Create a temp directory for any cruft my $TMPDIR="/tmp/mockcify"; system("mkdir -p $TMPDIR"); my $OUTDIR = "$TMPDIR/out/"; system("mkdir -p $OUTDIR"); my $INCDIR = "$TMPDIR/include/"; system("mkdir -p $INCDIR"); if (scalar(@ARGV == 0)) { printf(STDERR "ERROR Must supply at least one argument\n"); exit 1; } my $arg = shift @ARGV; ## Check only argument for debug vector if ($arg =~ /--cla[ng]/) { exit print clang_format(); } elsif ($arg =~ /--f[ilter]/) { exit print read_stdin_and_filter_file(); } elsif ($arg =~ /--l[ines]/) { exit print filter_lines(read_stdin_and_filter_file()); } elsif ($arg =~ /--i[nfo]/) { my ($incs, $types, $funcs) = parse_info(filter_lines(read_stdin_and_filter_file())); exit print @{$incs}, @{$types}, @{$funcs}; } elsif ($arg =~ /--co[mpile]/) { exit compilation_screen("mock_" . shift @ARGV); } elsif ($arg =~ /--cle[an]/) { exit system("mv $TMPDIR $TMPDIR.deleted"); } elsif ($arg =~ /--u[nittest]/) { print(STDERR "unit testing device"); } sub help { print <", $OUTDIR .$src_filename) or die $!; open($FH_HDR, ">", $OUTDIR .$hdr_filename) or die $!; } ### ### Phase 1: Read input file and apply single line filtering ### my $text = read_stdin_and_filter_file(); ### ### Phase 2: Apply Multiline filters ### $text = filter_lines($text); ## ## Phase 3: Extract required mock information ## my ($includes_ref, $typedefs_ref, $functions_ref, $usings_ref, $namespaces_ref) = parse_info($text); my @includes = @{$includes_ref}; my @typedefs = @{$typedefs_ref}; my @functions = @{$functions_ref}; my @namespaces = @{$namespaces_ref}; my @usings = @{$usings_ref}; @includes = reject_include_list(@includes); @functions = grep { parse_function_into_components ($_) } @functions; ## ## Phase 4: Output the mocks source and header ## print_source($FH_SRC); print_header($FH_HDR); close ($FH_SRC); close ($FH_HDR); ## Format the final source code files if (defined $src_filename) { system("clang-format", "-i", $OUTDIR . $src_filename); system("clang-format", "-i", $OUTDIR . $hdr_filename); } print(STDERR "Generated files:", $OUTDIR . $src_filename, " ", $OUTDIR . $hdr_filename, "\n"); if ($COMPILE_SCREEN_ENABLED) { my $rc = compilation_screen("mock_" . $namespace); exit ($rc == 256) ?1 : 0; } sub reject_include_list { my @incs = (); foreach (@_) { next if (/init_flags/); push(@incs, $_); } return @incs; } sub compile_screen_failed { my $src = shift @_; print STDERR <::iterator/) { return "static std::list v"; } elsif (/^std::list\::iterator/) { return "std::list"; } elsif (/reactor_status_t/) { return "REACTOR_STATUS_DONE"; } elsif (/tL2CAP_LE_RESULT_CODE/) { return "L2CAP_LE_RESULT_CONN_OK"; } elsif (/std::vector/) { return "retval"; } elsif (/tBT_TRANSPORT/) { return "BT_TRANSPORT_BR_EDR"; } elsif (/tSDP_STATUS/) { return "SDP_SUCCESS"; } elsif (/tGATT_STATUS/) { return "GATT_SUCCESS"; } elsif (/tHID_STATUS/) { return "HID_SUCCESS"; } elsif (/future_t\*/) { return "FUTURE_FAIL"; } elsif(/bt_status_t/) { return "BT_STATUS_SUCCESS"; } elsif(/.*module_t\*/) { return "nullptr"; } elsif(/btav_a2dp_codec_index_t/) { return "BTAV_A2DP_CODEC_INDEX_SOURCE_MIN"; } elsif(/tBTA_SDP_STATUS/) { return "BTA_SDP_SUCCESS"; } elsif(/tBTA_STATUS/) { return "BTA_SUCCESS"; } elsif(/tBTA_JV_STATUS/) { return "tBTA_JV_STATUS::SUCCESS"; } else { ## Decay to int type return "0"; } } ## ## Various print output boilerplate ### sub print_copyright { my $FH = shift @_; print $FH < body{[]($vars_commented_out_input_params){$return_statement}}; $return_type operator()($input_params) { ${return_keyword} body($function_param_names);}; }; extern struct $name $name; EOF } print $FH < #include EOF } sub print_mock_decl_src { my $FH = shift @_; print $FH < #include "test/common/mock_functions.h" EOF } sub print_defs { my $FH = shift @_; print $FH <; close $fh; $msg = "$file:$line: " . $lines[$line - 1]; } die "Assertion failed: $msg"; }