<commit_before>#!/bin/bash
#
# Copyright 2015 The Bazel Authors. All rights reserved.
#
# 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.

set -eu

# Load the test setup defined in the parent directory
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CURRENT_DIR}/../integration_test_setup.sh" \
  || { echo "integration_test_setup.sh not found!" >&2; exit 1; }

# Writes the C++ source files and a corresponding BUILD file for which to
# collect code coverage. The sources are a.cc, a.h and t.cc.
function setup_a_cc_lib_and_t_cc_test() {
  cat << EOF > BUILD
cc_library(
    name = "a",
    srcs = ["a.cc"],
    hdrs = ["a.h"],
)

cc_test(
    name = "t",
    srcs = ["t.cc"],
    deps = [":a"],
)
EOF

  cat << EOF > a.h
int a(bool what);
EOF

  cat << EOF > a.cc
#include "a.h"

int a(bool what) {
  if (what) {
    return 1;
  } else {
    return 2;
  }
}
EOF

  cat << EOF > t.cc
#include <stdio.h>
#include "a.h"

int main(void) {
  a(true);
}
EOF
}

# Asserts if the given expected coverage result is included in the given output
# file.
#
# - expected_coverage The expected result that must be included in the output.
# - output_file       The location of the coverage output file.
function assert_coverage_result() {
    local expected_coverage="${1}"; shift
    local output_file="${1}"; shift

    # Replace newlines with commas to facilitate the assertion.
    local expected_coverage_no_newlines="$( echo "$expected_coverage" | tr '\n' ',' )"
    local output_file_no_newlines="$( cat "$output_file" | tr '\n' ',' )"

    ( echo $output_file_no_newlines | grep  $expected_coverage_no_newlines ) \
        || fail "Expected coverage result
<$expected_coverage>
was not found in actual coverage report:
<$( cat "$output_file" )>"
}

# Returns the path of the code coverage report that was generated by Bazel by
# looking at the current $TEST_log. The method fails if TEST_log does not
# contain any coverage report for a passed test.
function get_coverage_file_path_from_test_log() {
  local ending_part="$(sed -n -e '/PASSED/,$p' "$TEST_log")"

  local coverage_file_path=$(grep -Eo "/[/a-zA-Z0-9\.\_\-]+\.dat$" <<< "$ending_part")
  [[ -e "$coverage_file_path" ]] || fail "Coverage output file does not exist!"
  echo "$coverage_file_path"
}

function test_cc_test_coverage_lcov() {
  local -r lcov_location=$(which lcov)
  if [[ ! -x "${lcov_location:-/usr/bin/lcov}" ]]; then
    echo "lcov not installed. Skipping test."
    return
  fi

  setup_a_cc_lib_and_t_cc_test

  bazel coverage --test_output=all --build_event_text_file=bep.txt //:t \
      &>"$TEST_log" || fail "Coverage for //:t failed"

  local coverage_output_file="$( get_coverage_file_path_from_test_log )"

  # Check the expected coverage for a.cc in the coverage file.
  # Note that t.cc is not included in the coverage report because it is
  # coming from a cc_test whose code is not included in the report by default.
  local expected_result_a_cc="SF:a.cc
FN:3,_Z1ab
FNDA:1,_Z1ab
FNF:1
FNH:1
DA:3,1
DA:4,1
DA:5,1
DA:7,0
LH:3
LF:4
end_of_record"
  assert_coverage_result "$expected_result_a_cc" "$coverage_output_file"

  # Verify that this is also true for cached coverage actions.
  bazel coverage --test_output=all --build_event_text_file=bep.txt //:t \
      &>"$TEST_log" || fail "Coverage for //:t failed"
  expect_log '//:t.*cached'
  # Verify the files are reported correctly in the build event protocol.
  assert_contains 'name: "test.lcov"' bep.txt
  assert_contains 'name: "baseline.lcov"' bep.txt
}

function test_cc_test_coverage_gcov() {
  local -r gcov_location=$(which gcov)
  if [[ ! -x ${gcov_location:-/usr/bin/gcov} ]]; then
    echo "gcov not installed. Skipping test."
    return
  fi

  "$gcov_location" -version | grep "LLVM" && \
      echo "gcov LLVM version not supported. Skipping test." && return
   # gcov -v | grep "gcov" outputs a line that looks like this:
   # gcov (Debian 7.3.0-5) 7.3.0
   local gcov_version="$(gcov -v | grep "gcov" | cut -d " " -f 4 | cut -d "." -f 1)"
    [ "$gcov_version" -lt 7 ] \
        && echo "gcov version before 7.0 is not supported. Skipping test." \
        && return

  setup_a_cc_lib_and_t_cc_test

  bazel coverage --experimental_cc_coverage --test_output=all \
     --build_event_text_file=bep.txt //:t &>"$TEST_log" \
     || fail "Coverage for //:t failed"

  local coverage_file_path="$( get_coverage_file_path_from_test_log )"

  # Check the expected coverage for a.cc in the coverage file.
  # Note that t.cc is not included in the coverage report because it is
  # coming from a cc_test whose code is not included in the report by default.
  local expected_result_a_cc="SF:a.cc
FN:3,_Z1ab
FNDA:1,_Z1ab
FNF:1
FNH:1
BA:4,2
BRF:1
BRH:1
DA:3,1
DA:4,1
DA:5,1
DA:7,0
LH:3
LF:4
end_of_record"
  assert_coverage_result "$expected_result_a_cc" "$coverage_file_path"

  # Verify that this is also true for cached coverage actions.
  bazel coverage --experimental_cc_coverage --test_output=all \
      --build_event_text_file=bep.txt //:t \
      &>"$TEST_log" || fail "Coverage for //:t failed"
  expect_log '//:t.*cached'
  # Verify the files are reported correctly in the build event protocol.
  assert_contains 'name: "test.lcov"' bep.txt
  assert_contains 'name: "baseline.lcov"' bep.txt
}

function test_cc_test_llvm_coverage_doesnt_fail() {
  local -r llvmprofdata=$(which llvm-profdata)
  if [[ ! -x ${llvmprofdata:-/usr/bin/llvm-profdata} ]]; then
    echo "llvm-profdata not installed. Skipping test."
    return
  fi

  local -r clang_tool=$(which clang++)
  if [[ ! -x ${clang_tool:-/usr/bin/clang_tool} ]]; then
    echo "clang++ not installed. Skipping test."
    return
  fi

  setup_a_cc_lib_and_t_cc_test

  # Only test that bazel coverage doesn't crash when invoked for llvm native
  # coverage.
  BAZEL_USE_LLVM_NATIVE_COVERAGE=1 GCOV=$llvmprofdata CC=$clang_tool \<commit_msg>Add virtual includes coverage test.<commit_after>#!/bin/bash
#
# Copyright 2015 The Bazel Authors. All rights reserved.
#
# 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.

set -eu

# Load the test setup defined in the parent directory
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CURRENT_DIR}/../integration_test_setup.sh" \
  || { echo "integration_test_setup.sh not found!" >&2; exit 1; }

# Writes the C++ source files and a corresponding BUILD file for which to
# collect code coverage. The sources are a.cc, a.h and t.cc.
function setup_a_cc_lib_and_t_cc_test() {
  cat << EOF > BUILD
cc_library(
    name = "a",
    srcs = ["a.cc"],
    hdrs = ["a.h"],
)

cc_test(
    name = "t",
    srcs = ["t.cc"],
    deps = [":a"],
)
EOF

  cat << EOF > a.h
int a(bool what);
EOF

  cat << EOF > a.cc
#include "a.h"

int a(bool what) {
  if (what) {
    return 1;
  } else {
    return 2;
  }
}
EOF

  cat << EOF > t.cc
#include <stdio.h>
#include "a.h"

int main(void) {
  a(true);
}
EOF
}

# Asserts if the given expected coverage result is included in the given output
# file.
#
# - expected_coverage The expected result that must be included in the output.
# - output_file       The location of the coverage output file.
function assert_coverage_result() {
    local expected_coverage="${1}"; shift
    local output_file="${1}"; shift

    # Replace newlines with commas to facilitate the assertion.
    local expected_coverage_no_newlines="$( echo "$expected_coverage" | tr '\n' ',' )"
    local output_file_no_newlines="$( cat "$output_file" | tr '\n' ',' )"

    ( echo $output_file_no_newlines | grep  $expected_coverage_no_newlines ) \
        || fail "Expected coverage result
<$expected_coverage>
was not found in actual coverage report:
<$( cat "$output_file" )>"
}

# Returns the path of the code coverage report that was generated by Bazel by
# looking at the current $TEST_log. The method fails if TEST_log does not
# contain any coverage report for a passed test.
function get_coverage_file_path_from_test_log() {
  local ending_part="$(sed -n -e '/PASSED/,$p' "$TEST_log")"

  local coverage_file_path=$(grep -Eo "/[/a-zA-Z0-9\.\_\-]+\.dat$" <<< "$ending_part")
  [[ -e "$coverage_file_path" ]] || fail "Coverage output file does not exist!"
  echo "$coverage_file_path"
}

function test_cc_test_coverage_lcov() {
  local -r lcov_location=$(which lcov)
  if [[ ! -x "${lcov_location:-/usr/bin/lcov}" ]]; then
    echo "lcov not installed. Skipping test."
    return
  fi

  setup_a_cc_lib_and_t_cc_test

  bazel coverage --test_output=all --build_event_text_file=bep.txt //:t \
      &>"$TEST_log" || fail "Coverage for //:t failed"

  local coverage_output_file="$( get_coverage_file_path_from_test_log )"

  # Check the expected coverage for a.cc in the coverage file.
  # Note that t.cc is not included in the coverage report because it is
  # coming from a cc_test whose code is not included in the report by default.
  local expected_result_a_cc="SF:a.cc
FN:3,_Z1ab
FNDA:1,_Z1ab
FNF:1
FNH:1
DA:3,1
DA:4,1
DA:5,1
DA:7,0
LH:3
LF:4
end_of_record"
  assert_coverage_result "$expected_result_a_cc" "$coverage_output_file"

  # Verify that this is also true for cached coverage actions.
  bazel coverage --test_output=all --build_event_text_file=bep.txt //:t \
      &>"$TEST_log" || fail "Coverage for //:t failed"
  expect_log '//:t.*cached'
  # Verify the files are reported correctly in the build event protocol.
  assert_contains 'name: "test.lcov"' bep.txt
  assert_contains 'name: "baseline.lcov"' bep.txt
}

function test_cc_test_coverage_gcov() {
  local -r gcov_location=$(which gcov)
  if [[ ! -x ${gcov_location:-/usr/bin/gcov} ]]; then
    echo "gcov not installed. Skipping test."
    return
  fi

  "$gcov_location" -version | grep "LLVM" && \
      echo "gcov LLVM version not supported. Skipping test." && return
   # gcov -v | grep "gcov" outputs a line that looks like this:
   # gcov (Debian 7.3.0-5) 7.3.0
   local gcov_version="$(gcov -v | grep "gcov" | cut -d " " -f 4 | cut -d "." -f 1)"
    [ "$gcov_version" -lt 7 ] \
        && echo "gcov version before 7.0 is not supported. Skipping test." \
        && return

  setup_a_cc_lib_and_t_cc_test

  bazel coverage --experimental_cc_coverage --test_output=all \
     --build_event_text_file=bep.txt //:t &>"$TEST_log" \
     || fail "Coverage for //:t failed"

  local coverage_file_path="$( get_coverage_file_path_from_test_log )"

  # Check the expected coverage for a.cc in the coverage file.
  # Note that t.cc is not included in the coverage report because it is
  # coming from a cc_test whose code is not included in the report by default.
  local expected_result_a_cc="SF:a.cc
FN:3,_Z1ab
FNDA:1,_Z1ab
FNF:1
FNH:1
BA:4,2
BRF:1
BRH:1
DA:3,1
DA:4,1
DA:5,1
DA:7,0
LH:3
LF:4
end_of_record"
  assert_coverage_result "$expected_result_a_cc" "$coverage_file_path"

  # Verify that this is also true for cached coverage actions.
  bazel coverage --experimental_cc_coverage --test_output=all \
      --build_event_text_file=bep.txt //:t \
      &>"$TEST_log" || fail "Coverage for //:t failed"
  expect_log '//:t.*cached'
  # Verify the files are reported correctly in the build event protocol.
  assert_contains 'name: "test.lcov"' bep.txt
  assert_contains 'name: "baseline.lcov"' bep.txt
}

# TODO(#6254): Enable this test when #6254 is fixed.
function SKIP_test_cc_test_coverage_gcov_virtual_includes() {
  local -r gcov_location=$(which gcov)
  if [[ ! -x ${gcov_location:-/usr/bin/gcov} ]]; then
    echo "gcov not installed. Skipping test."
    return
  fi

  "$gcov_location" -version | grep "LLVM" && \
      echo "gcov LLVM version not supported. Skipping test." && return
   # gcov -v | grep "gcov" outputs a line that looks like this:
   # gcov (Debian 7.3.0-5) 7.3.0
   local gcov_version="$(gcov -v | grep "gcov" | cut -d " " -f 4 | cut -d "." -f 1)"
    [ "$gcov_version" -lt 7 ] \
        && echo "gcov version before 7.0 is not supported. Skipping test." \
        && return

  ########### Setup source files and BUILD file ###########
  mkdir -p examples/cpp
 cat << EOF > examples/cpp/BUILD
cc_library(
    name = "a_header",
    hdrs = ["foo/bar/baz/a_header.h"],
    strip_include_prefix = "foo",
    include_prefix = "yin/yang",
)

cc_library(
    name = "hello-lib",
    srcs = ["hello-lib.cc"],
    hdrs = ["hello-lib.h"],
    deps = [":a_header"],
)

cc_test(
    name = "hello-world_test",
    srcs = ["hello-world.cc"],
    deps = [":hello-lib"],
)
EOF
  mkdir -p examples/cpp/foo/bar/baz
  cat << EOF > examples/cpp/foo/bar/baz/a_header.h
#include<iostream>
using namespace std;

class A {
public:
	void cout_whatever() const {
		cout << "Whatever";
	}
};
EOF

  cat << EOF > examples/cpp/hello-lib.h
#ifndef EXAMPLES_CPP_HELLO_LIB_H_
#define EXAMPLES_CPP_HELLO_LIB_H_

#include <string>
#include <memory>
#include "yin/yang/bar/baz/a_header.h"

namespace hello {

class HelloLib {
 public:
  explicit HelloLib(const std::string &greeting);

  void greet(const std::string &thing);

 private:
  std::auto_ptr<const std::string> greeting_;
};
}  // namespace hello
#endif  // EXAMPLES_CPP_HELLO_LIB_H_
EOF

  cat << EOF > examples/cpp/hello-lib.cc
#include "examples/cpp/hello-lib.h"

#include <iostream>

using std::cout;
using std::endl;
using std::string;

namespace hello {

HelloLib::HelloLib(const string& greeting) : greeting_(new string(greeting)) {
}

void HelloLib::greet(const string& thing) {
  cout << *greeting_ << " " << thing << endl;
  A* a = new A();
  a->cout_whatever();
}
}  // namespace hello
EOF

  cat << EOF > examples/cpp/hello-world.cc
#include "examples/cpp/hello-lib.h"

#include <string>

using hello::HelloLib;
using std::string;

int main(int argc, char** argv) {
  HelloLib lib("Hello");
  string thing = "world";
  if (argc > 1) {
    thing = argv[1];
  }
  lib.greet(thing);
  return 0;
}
EOF

  ########### Run bazel coverage ###########
  bazel coverage --experimental_cc_coverage --test_output=all //examples/cpp:hello-world_test &>"$TEST_log" \
     || fail "Coverage for //examples/cpp:hello-world_test failed"

  ########### Assert coverage results. ###########
  local coverage_file_path="$( get_coverage_file_path_from_test_log )"
  local expected_result_hello_lib="SF:examples/cpp/hello-lib.cc
FN:19,_GLOBAL__sub_I_hello_lib.cc
FN:19,_Z41__static_initialization_and_destruction_0ii
FN:14,_ZN5hello8HelloLib5greetERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
FN:11,_ZN5hello8HelloLibC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
FNDA:1,_GLOBAL__sub_I_hello_lib.cc
FNDA:1,_Z41__static_initialization_and_destruction_0ii
FNDA:1,_ZN5hello8HelloLib5greetERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
FNDA:1,_ZN5hello8HelloLibC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
FNF:4
FNH:4
BA:11,2
BA:19,2
BRF:2
BRH:2
DA:11,1
DA:12,1
DA:14,1
DA:15,1
DA:16,1
DA:17,1
DA:18,1
DA:19,3
LH:8
LF:8
end_of_record"
  assert_coverage_result "$expected_result_hello_lib" "$coverage_file_path"

  local expected_result_a_header="SF:examples/cpp/foo/bar/baz/a_header.h
FN:9,_ZNK1A13cout_whateverEv
FNDA:1,_ZNK1A13cout_whateverEv
FNF:1
FNH:1
DA:9,1
DA:10,1
DA:11,1
LH:3
LF:3
end_of_record"
  assert_coverage_result "$expected_result_a_header" "$coverage_file_path"

  local coverage_result_hello_lib_header="SF:examples/cpp/hello-lib.h
FN:12,_ZN5hello8HelloLibD2Ev
FNDA:1,_ZN5hello8HelloLibD2Ev
FNF:1
FNH:1
DA:12,1
LH:1
LF:1
end_of_record"
  assert_coverage_result "$coverage_result_hello_lib_header" "$coverage_file_path"
}

function test_cc_test_llvm_coverage_doesnt_fail() {
  local -r llvmprofdata=$(which llvm-profdata)
  if [[ ! -x ${llvmprofdata:-/usr/bin/llvm-profdata} ]]; then
    echo "llvm-profdata not installed. Skipping test."
    return
  fi

  local -r clang_tool=$(which clang++)
  if [[ ! -x ${clang_tool:-/usr/bin/clang_tool} ]]; then
    echo "clang++ not installed. Skipping test."
    return
  fi

  setup_a_cc_lib_and_t_cc_test

  # Only test that bazel coverage doesn't crash when invoked for llvm native
  # coverage.
  BAZEL_USE_LLVM_NATIVE_COVERAGE=1 GCOV=$llvmprofdata CC=$clang_tool \
{'fraction_non_alphanumeric': 0.1274163130598774, 'fraction_numerical': 0.016796322489391797, 'mean_word_length': 3.9285506825442926, 'pattern_counts': {'":': 4, '<': 57, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2391384', 'n_tokens_mistral': 6359, 'n_tokens_neox': 6091, 'n_words': 1705}