brintos

brintos / llvm-project-archived public Read only

0
0
Text · 44.8 KiB · b268aa7 Raw
1175 lines · cpp
1//===- unittest/ProfileData/CoverageMappingTest.cpp -------------------------=//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ProfileData/Coverage/CoverageMapping.h"10#include "llvm/ProfileData/Coverage/CoverageMappingReader.h"11#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"12#include "llvm/ProfileData/InstrProfReader.h"13#include "llvm/ProfileData/InstrProfWriter.h"14#include "llvm/Support/raw_ostream.h"15#include "llvm/Testing/Support/Error.h"16#include "llvm/Testing/Support/SupportHelpers.h"17#include "gtest/gtest.h"18 19#include <map>20#include <ostream>21#include <utility>22 23using namespace llvm;24using namespace coverage;25 26[[nodiscard]] static ::testing::AssertionResult27ErrorEquals(Error E, coveragemap_error Expected_Err,28            const std::string &Expected_Msg = std::string()) {29  coveragemap_error Found;30  std::string Msg;31  std::string FoundMsg;32  handleAllErrors(std::move(E), [&](const CoverageMapError &CME) {33    Found = CME.get();34    Msg = CME.getMessage();35    FoundMsg = CME.message();36  });37  if (Expected_Err == Found && Msg == Expected_Msg)38    return ::testing::AssertionSuccess();39  return ::testing::AssertionFailure() << "error: " << FoundMsg << "\n";40}41 42namespace llvm {43namespace coverage {44void PrintTo(const Counter &C, ::std::ostream *os) {45  if (C.isZero())46    *os << "Zero";47  else if (C.isExpression())48    *os << "Expression " << C.getExpressionID();49  else50    *os << "Counter " << C.getCounterID();51}52 53void PrintTo(const CoverageSegment &S, ::std::ostream *os) {54  *os << "CoverageSegment(" << S.Line << ", " << S.Col << ", ";55  if (S.HasCount)56    *os << S.Count << ", ";57  *os << (S.IsRegionEntry ? "true" : "false") << ")";58}59}60}61 62namespace {63 64struct OutputFunctionCoverageData {65  StringRef Name;66  uint64_t Hash;67  std::vector<std::string> FilenamesStorage;68  std::vector<StringRef> Filenames;69  std::vector<CounterMappingRegion> Regions;70  std::vector<CounterExpression> Expressions;71 72  OutputFunctionCoverageData() : Hash(0) {}73 74  OutputFunctionCoverageData(OutputFunctionCoverageData &&OFCD)75      : Name(OFCD.Name), Hash(OFCD.Hash),76        FilenamesStorage(std::move(OFCD.FilenamesStorage)),77        Filenames(std::move(OFCD.Filenames)), Regions(std::move(OFCD.Regions)) {78  }79 80  OutputFunctionCoverageData(const OutputFunctionCoverageData &) = delete;81  OutputFunctionCoverageData &82  operator=(const OutputFunctionCoverageData &) = delete;83  OutputFunctionCoverageData &operator=(OutputFunctionCoverageData &&) = delete;84 85  void fillCoverageMappingRecord(CoverageMappingRecord &Record) const {86    Record.FunctionName = Name;87    Record.FunctionHash = Hash;88    Record.Filenames = Filenames;89    Record.Expressions = Expressions;90    Record.MappingRegions = Regions;91  }92};93 94struct CoverageMappingReaderMock : CoverageMappingReader {95  ArrayRef<OutputFunctionCoverageData> Functions;96 97  CoverageMappingReaderMock(ArrayRef<OutputFunctionCoverageData> Functions)98      : Functions(Functions) {}99 100  Error readNextRecord(CoverageMappingRecord &Record) override {101    if (Functions.empty())102      return make_error<CoverageMapError>(coveragemap_error::eof);103 104    Functions.front().fillCoverageMappingRecord(Record);105    Functions = Functions.slice(1);106 107    return Error::success();108  }109};110 111struct InputFunctionCoverageData {112  // Maps the global file index from CoverageMappingTest.Files113  // to the index of that file within this function. We can't just use114  // global file indexes here because local indexes have to be dense.115  // This map is used during serialization to create the virtual file mapping116  // (from local fileId to global Index) in the head of the per-function117  // coverage mapping data.118  SmallDenseMap<unsigned, unsigned> ReverseVirtualFileMapping;119  std::string Name;120  uint64_t Hash;121  std::vector<CounterMappingRegion> Regions;122  std::vector<CounterExpression> Expressions;123 124  InputFunctionCoverageData(std::string Name, uint64_t Hash)125      : Name(std::move(Name)), Hash(Hash) {}126 127  InputFunctionCoverageData(InputFunctionCoverageData &&IFCD)128      : ReverseVirtualFileMapping(std::move(IFCD.ReverseVirtualFileMapping)),129        Name(std::move(IFCD.Name)), Hash(IFCD.Hash),130        Regions(std::move(IFCD.Regions)) {}131 132  InputFunctionCoverageData(const InputFunctionCoverageData &) = delete;133  InputFunctionCoverageData &134  operator=(const InputFunctionCoverageData &) = delete;135  InputFunctionCoverageData &operator=(InputFunctionCoverageData &&) = delete;136};137 138struct CoverageMappingTest : ::testing::TestWithParam<std::tuple<bool, bool>> {139  bool UseMultipleReaders;140  StringMap<unsigned> Files;141  std::vector<InputFunctionCoverageData> InputFunctions;142  std::vector<OutputFunctionCoverageData> OutputFunctions;143 144  InstrProfWriter ProfileWriter;145  std::unique_ptr<IndexedInstrProfReader> ProfileReader;146 147  std::unique_ptr<CoverageMapping> LoadedCoverage;148 149  void SetUp() override {150    ProfileWriter.setOutputSparse(std::get<0>(GetParam()));151    UseMultipleReaders = std::get<1>(GetParam());152  }153 154  unsigned getGlobalFileIndex(StringRef Name) {155    auto R = Files.find(Name);156    if (R != Files.end())157      return R->second;158    unsigned Index = Files.size() + 1;159    Files.try_emplace(Name, Index);160    return Index;161  }162 163  // Return the file index of file 'Name' for the current function.164  // Add the file into the global map if necessary.165  // See also InputFunctionCoverageData::ReverseVirtualFileMapping166  // for additional comments.167  unsigned getFileIndexForFunction(StringRef Name) {168    unsigned GlobalIndex = getGlobalFileIndex(Name);169    auto &CurrentFunctionFileMapping =170        InputFunctions.back().ReverseVirtualFileMapping;171    auto R = CurrentFunctionFileMapping.find(GlobalIndex);172    if (R != CurrentFunctionFileMapping.end())173      return R->second;174    unsigned IndexInFunction = CurrentFunctionFileMapping.size();175    CurrentFunctionFileMapping.insert(176        std::make_pair(GlobalIndex, IndexInFunction));177    return IndexInFunction;178  }179 180  void startFunction(StringRef FuncName, uint64_t Hash) {181    InputFunctions.emplace_back(FuncName.str(), Hash);182  }183 184  void addCMR(Counter C, StringRef File, unsigned LS, unsigned CS, unsigned LE,185              unsigned CE, bool Skipped = false) {186    auto &Regions = InputFunctions.back().Regions;187    unsigned FileID = getFileIndexForFunction(File);188    Regions.push_back(189        Skipped ? CounterMappingRegion::makeSkipped(FileID, LS, CS, LE, CE)190                : CounterMappingRegion::makeRegion(C, FileID, LS, CS, LE, CE));191  }192 193  void addSkipped(StringRef File, unsigned LS, unsigned CS, unsigned LE,194                  unsigned CE) {195    addCMR(Counter::getZero(), File, LS, CS, LE, CE, true);196  }197 198  void addMCDCDecisionCMR(unsigned Mask, uint16_t NC, StringRef File,199                          unsigned LS, unsigned CS, unsigned LE, unsigned CE) {200    auto &Regions = InputFunctions.back().Regions;201    unsigned FileID = getFileIndexForFunction(File);202    Regions.push_back(CounterMappingRegion::makeDecisionRegion(203        mcdc::DecisionParameters{Mask, NC}, FileID, LS, CS, LE, CE));204  }205 206  void addMCDCBranchCMR(Counter C1, Counter C2, mcdc::ConditionID ID,207                        mcdc::ConditionIDs Conds, StringRef File, unsigned LS,208                        unsigned CS, unsigned LE, unsigned CE) {209    auto &Regions = InputFunctions.back().Regions;210    unsigned FileID = getFileIndexForFunction(File);211    Regions.push_back(CounterMappingRegion::makeBranchRegion(212        C1, C2, FileID, LS, CS, LE, CE, mcdc::BranchParameters{ID, Conds}));213  }214 215  void addExpansionCMR(StringRef File, StringRef ExpandedFile, unsigned LS,216                       unsigned CS, unsigned LE, unsigned CE) {217    InputFunctions.back().Regions.push_back(CounterMappingRegion::makeExpansion(218        getFileIndexForFunction(File), getFileIndexForFunction(ExpandedFile),219        LS, CS, LE, CE));220  }221 222  void addExpression(CounterExpression CE) {223    InputFunctions.back().Expressions.push_back(CE);224  }225 226  std::string writeCoverageRegions(InputFunctionCoverageData &Data) {227    SmallVector<unsigned, 8> FileIDs(Data.ReverseVirtualFileMapping.size());228    for (const auto &E : Data.ReverseVirtualFileMapping)229      FileIDs[E.second] = E.first;230    std::string Coverage;231    llvm::raw_string_ostream OS(Coverage);232    CoverageMappingWriter(FileIDs, Data.Expressions, Data.Regions).write(OS);233    return OS.str();234  }235 236  void readCoverageRegions(const std::string &Coverage,237                           OutputFunctionCoverageData &Data) {238    // +1 here since `Files` (filename to index map) uses 1-based index.239    Data.FilenamesStorage.resize(Files.size() + 1);240    for (const auto &E : Files)241      Data.FilenamesStorage[E.getValue()] = E.getKey().str();242    ArrayRef<std::string> FilenameRefs = llvm::ArrayRef(Data.FilenamesStorage);243    RawCoverageMappingReader Reader(Coverage, FilenameRefs, Data.Filenames,244                                    Data.Expressions, Data.Regions);245    EXPECT_THAT_ERROR(Reader.read(), Succeeded());246  }247 248  void writeAndReadCoverageRegions(bool EmitFilenames = true) {249    OutputFunctions.resize(InputFunctions.size());250    for (unsigned I = 0; I < InputFunctions.size(); ++I) {251      std::string Regions = writeCoverageRegions(InputFunctions[I]);252      readCoverageRegions(Regions, OutputFunctions[I]);253      OutputFunctions[I].Name = InputFunctions[I].Name;254      OutputFunctions[I].Hash = InputFunctions[I].Hash;255      if (!EmitFilenames)256        OutputFunctions[I].Filenames.clear();257    }258  }259 260  void readProfCounts() {261    auto Profile = ProfileWriter.writeBuffer();262    auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile));263    EXPECT_THAT_ERROR(ReaderOrErr.takeError(), Succeeded());264    ProfileReader = std::move(ReaderOrErr.get());265  }266 267  Expected<std::unique_ptr<CoverageMapping>> readOutputFunctions() {268    std::vector<std::unique_ptr<CoverageMappingReader>> CoverageReaders;269    if (UseMultipleReaders) {270      for (const auto &OF : OutputFunctions) {271        ArrayRef<OutputFunctionCoverageData> Funcs(OF);272        CoverageReaders.push_back(273            std::make_unique<CoverageMappingReaderMock>(Funcs));274      }275    } else {276      ArrayRef<OutputFunctionCoverageData> Funcs(OutputFunctions);277      CoverageReaders.push_back(278          std::make_unique<CoverageMappingReaderMock>(Funcs));279    }280    auto ProfileReaderRef = std::make_optional(281        std::reference_wrapper<IndexedInstrProfReader>(*ProfileReader));282    return CoverageMapping::load(CoverageReaders, ProfileReaderRef);283  }284 285  Error loadCoverageMapping(bool EmitFilenames = true) {286    readProfCounts();287    writeAndReadCoverageRegions(EmitFilenames);288    auto CoverageOrErr = readOutputFunctions();289    if (!CoverageOrErr)290      return CoverageOrErr.takeError();291    LoadedCoverage = std::move(CoverageOrErr.get());292    return Error::success();293  }294};295 296TEST(CoverageMappingTest, expression_subst) {297  CounterExpressionBuilder Builder;298  CounterExpressionBuilder::SubstMap MapToExpand;299 300  auto C = [](unsigned ID) { return Counter::getCounter(ID); };301  auto A = [&](Counter LHS, Counter RHS) { return Builder.add(LHS, RHS); };302  // returns {E, N} in clangCodeGen303  auto getBranchCounterPair = [&](Counter E, Counter P, Counter N) {304    auto Skipped = Builder.subtract(P, E);305    MapToExpand[N] = Builder.subst(Skipped, MapToExpand);306  };307 308  auto E18 = C(5);309  auto P18 = C(2);310  auto S18 = C(18);311  // #18 => (#2 - #5)312  getBranchCounterPair(E18, P18, S18);313 314  auto E22 = S18;315  auto P22 = C(0);316  auto S22 = C(22);317  // #22 => #0 - (#2 - #5)318  getBranchCounterPair(E22, P22, S22);319 320  auto E28 = A(A(C(9), C(11)), C(14));321  auto P28 = S22;322  auto S28 = C(28);323  // #28 => (((((#0 + #5) - #2) - #9) - #11) - #14)324  getBranchCounterPair(E28, P28, S28);325 326  auto LHS = A(E28, A(S28, S18));327  auto RHS = C(0);328 329  // W/o subst, LHS cannot be reduced.330  ASSERT_FALSE(Builder.subtract(LHS, RHS).isZero());331  // W/ subst, C(18) and C(28) in LHS will be reduced.332  ASSERT_TRUE(Builder.subst(Builder.subtract(LHS, RHS), MapToExpand).isZero());333}334 335TEST_P(CoverageMappingTest, basic_write_read) {336  startFunction("func", 0x1234);337  addCMR(Counter::getCounter(0), "foo", 1, 1, 1, 1);338  addCMR(Counter::getCounter(1), "foo", 2, 1, 2, 2);339  addCMR(Counter::getZero(),     "foo", 3, 1, 3, 4);340  addCMR(Counter::getCounter(2), "foo", 4, 1, 4, 8);341  addCMR(Counter::getCounter(3), "bar", 1, 2, 3, 4);342 343  writeAndReadCoverageRegions();344  ASSERT_EQ(1u, InputFunctions.size());345  ASSERT_EQ(1u, OutputFunctions.size());346  InputFunctionCoverageData &Input = InputFunctions.back();347  OutputFunctionCoverageData &Output = OutputFunctions.back();348 349  size_t N = ArrayRef(Input.Regions).size();350  ASSERT_EQ(N, Output.Regions.size());351  for (size_t I = 0; I < N; ++I) {352    ASSERT_EQ(Input.Regions[I].Count, Output.Regions[I].Count);353    ASSERT_EQ(Input.Regions[I].FileID, Output.Regions[I].FileID);354    ASSERT_EQ(Input.Regions[I].startLoc(), Output.Regions[I].startLoc());355    ASSERT_EQ(Input.Regions[I].endLoc(), Output.Regions[I].endLoc());356    ASSERT_EQ(Input.Regions[I].Kind, Output.Regions[I].Kind);357  }358}359 360TEST_P(CoverageMappingTest, correct_deserialize_for_more_than_two_files) {361  const char *FileNames[] = {"bar", "baz", "foo"};362  static const unsigned N = std::size(FileNames);363 364  startFunction("func", 0x1234);365  for (unsigned I = 0; I < N; ++I)366    // Use LineStart to hold the index of the file name367    // in order to preserve that information during possible sorting of CMRs.368    addCMR(Counter::getCounter(0), FileNames[I], I, 1, I, 1);369 370  writeAndReadCoverageRegions();371  ASSERT_EQ(1u, OutputFunctions.size());372  OutputFunctionCoverageData &Output = OutputFunctions.back();373 374  ASSERT_EQ(N, Output.Regions.size());375  ASSERT_EQ(N, Output.Filenames.size());376 377  for (unsigned I = 0; I < N; ++I) {378    ASSERT_GT(N, Output.Regions[I].FileID);379    ASSERT_GT(N, Output.Regions[I].LineStart);380    EXPECT_EQ(FileNames[Output.Regions[I].LineStart],381              Output.Filenames[Output.Regions[I].FileID]);382  }383}384 385static const auto Err = [](Error E) { FAIL(); };386 387TEST_P(CoverageMappingTest, load_coverage_for_more_than_two_files) {388  ProfileWriter.addRecord({"func", 0x1234, {0}}, Err);389 390  const char *FileNames[] = {"bar", "baz", "foo"};391  static const unsigned N = std::size(FileNames);392 393  startFunction("func", 0x1234);394  for (unsigned I = 0; I < N; ++I)395    // Use LineStart to hold the index of the file name396    // in order to preserve that information during possible sorting of CMRs.397    addCMR(Counter::getCounter(0), FileNames[I], I, 1, I, 1);398 399  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());400 401  for (unsigned I = 0; I < N; ++I) {402    CoverageData Data = LoadedCoverage->getCoverageForFile(FileNames[I]);403    ASSERT_TRUE(!Data.empty());404    EXPECT_EQ(I, Data.begin()->Line);405  }406}407 408TEST_P(CoverageMappingTest, load_coverage_with_bogus_function_name) {409  ProfileWriter.addRecord({"", 0x1234, {10}}, Err);410  startFunction("", 0x1234);411  addCMR(Counter::getCounter(0), "foo", 1, 1, 5, 5);412  EXPECT_TRUE(ErrorEquals(loadCoverageMapping(), coveragemap_error::malformed,413                          "record function name is empty"));414}415 416TEST_P(CoverageMappingTest, load_coverage_for_several_functions) {417  ProfileWriter.addRecord({"func1", 0x1234, {10}}, Err);418  ProfileWriter.addRecord({"func2", 0x2345, {20}}, Err);419 420  startFunction("func1", 0x1234);421  addCMR(Counter::getCounter(0), "foo", 1, 1, 5, 5);422 423  startFunction("func2", 0x2345);424  addCMR(Counter::getCounter(0), "bar", 2, 2, 6, 6);425 426  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());427 428  const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();429  EXPECT_EQ(2, std::distance(FunctionRecords.begin(), FunctionRecords.end()));430  for (const auto &FunctionRecord : FunctionRecords) {431    CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);432    std::vector<CoverageSegment> Segments(Data.begin(), Data.end());433    ASSERT_EQ(2U, Segments.size());434    if (FunctionRecord.Name == "func1") {435      EXPECT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]);436      EXPECT_EQ(CoverageSegment(5, 5, false), Segments[1]);437    } else {438      ASSERT_EQ("func2", FunctionRecord.Name);439      EXPECT_EQ(CoverageSegment(2, 2, 20, true), Segments[0]);440      EXPECT_EQ(CoverageSegment(6, 6, false), Segments[1]);441    }442  }443}444 445TEST_P(CoverageMappingTest, create_combined_regions) {446  ProfileWriter.addRecord({"func1", 0x1234, {1, 2, 3}}, Err);447  startFunction("func1", 0x1234);448 449  // Given regions which start at the same location, emit a segment for the450  // last region.451  addCMR(Counter::getCounter(0), "file1", 1, 1, 2, 2);452  addCMR(Counter::getCounter(1), "file1", 1, 1, 2, 2);453  addCMR(Counter::getCounter(2), "file1", 1, 1, 2, 2);454 455  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());456  const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();457  const auto &FunctionRecord = *FunctionRecords.begin();458  CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);459  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());460 461  ASSERT_EQ(2U, Segments.size());462  EXPECT_EQ(CoverageSegment(1, 1, 6, true), Segments[0]);463  EXPECT_EQ(CoverageSegment(2, 2, false), Segments[1]);464}465 466TEST_P(CoverageMappingTest, skipped_segments_have_no_count) {467  ProfileWriter.addRecord({"func1", 0x1234, {1}}, Err);468  startFunction("func1", 0x1234);469 470  addCMR(Counter::getCounter(0), "file1", 1, 1, 5, 5);471  addCMR(Counter::getCounter(0), "file1", 5, 1, 5, 5, /*Skipped=*/true);472 473  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());474  const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();475  const auto &FunctionRecord = *FunctionRecords.begin();476  CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);477  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());478 479  ASSERT_EQ(3U, Segments.size());480  EXPECT_EQ(CoverageSegment(1, 1, 1, true), Segments[0]);481  EXPECT_EQ(CoverageSegment(5, 1, true), Segments[1]);482  EXPECT_EQ(CoverageSegment(5, 5, false), Segments[2]);483}484 485TEST_P(CoverageMappingTest, multiple_regions_end_after_parent_ends) {486  ProfileWriter.addRecord({"func1", 0x1234, {1, 0}}, Err);487  startFunction("func1", 0x1234);488 489  // 1| F{ a{490  // 2|491  // 3|    a} b{ c{492  // 4|493  // 5|    b}494  // 6|495  // 7| c} d{   e{496  // 8|497  // 9| d}      e} F}498  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); // < F499  addCMR(Counter::getCounter(0), "file1", 1, 1, 3, 5); // < a500  addCMR(Counter::getCounter(0), "file1", 3, 5, 5, 4); // < b501  addCMR(Counter::getCounter(1), "file1", 3, 5, 7, 3); // < c502  addCMR(Counter::getCounter(1), "file1", 7, 3, 9, 2); // < d503  addCMR(Counter::getCounter(1), "file1", 7, 7, 9, 7); // < e504 505  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());506  const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();507  const auto &FunctionRecord = *FunctionRecords.begin();508  CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);509  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());510 511  // Old output (not sorted or unique):512  //   Segment at 1:1 with count 1513  //   Segment at 1:1 with count 1514  //   Segment at 3:5 with count 1515  //   Segment at 3:5 with count 0516  //   Segment at 3:5 with count 1517  //   Segment at 5:4 with count 0518  //   Segment at 7:3 with count 1519  //   Segment at 7:3 with count 0520  //   Segment at 7:7 with count 0521  //   Segment at 9:7 with count 0522  //   Segment at 9:2 with count 1523  //   Top level segment at 9:9524 525  // New output (sorted and unique):526  //   Segment at 1:1 (count = 1), RegionEntry527  //   Segment at 3:5 (count = 1), RegionEntry528  //   Segment at 5:4 (count = 0)529  //   Segment at 7:3 (count = 0), RegionEntry530  //   Segment at 7:7 (count = 0), RegionEntry531  //   Segment at 9:2 (count = 0)532  //   Segment at 9:7 (count = 1)533  //   Segment at 9:9 (count = 0), Skipped534 535  ASSERT_EQ(8U, Segments.size());536  EXPECT_EQ(CoverageSegment(1, 1, 1, true), Segments[0]);537  EXPECT_EQ(CoverageSegment(3, 5, 1, true), Segments[1]);538  EXPECT_EQ(CoverageSegment(5, 4, 0, false), Segments[2]);539  EXPECT_EQ(CoverageSegment(7, 3, 0, true), Segments[3]);540  EXPECT_EQ(CoverageSegment(7, 7, 0, true), Segments[4]);541  EXPECT_EQ(CoverageSegment(9, 2, 0, false), Segments[5]);542  EXPECT_EQ(CoverageSegment(9, 7, 1, false), Segments[6]);543  EXPECT_EQ(CoverageSegment(9, 9, false), Segments[7]);544}545 546TEST_P(CoverageMappingTest, multiple_completed_segments_at_same_loc) {547  ProfileWriter.addRecord({"func1", 0x1234, {0, 1, 2}}, Err);548  startFunction("func1", 0x1234);549 550  // PR35495551  addCMR(Counter::getCounter(1), "file1", 2, 1, 18, 2);552  addCMR(Counter::getCounter(0), "file1", 8, 10, 14, 6);553  addCMR(Counter::getCounter(0), "file1", 8, 12, 14, 6);554  addCMR(Counter::getCounter(1), "file1", 9, 1, 14, 6);555  addCMR(Counter::getCounter(2), "file1", 11, 13, 11, 14);556 557  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());558  const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();559  const auto &FunctionRecord = *FunctionRecords.begin();560  CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);561  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());562 563  ASSERT_EQ(7U, Segments.size());564  EXPECT_EQ(CoverageSegment(2, 1, 1, true), Segments[0]);565  EXPECT_EQ(CoverageSegment(8, 10, 0, true), Segments[1]);566  EXPECT_EQ(CoverageSegment(8, 12, 0, true), Segments[2]);567  EXPECT_EQ(CoverageSegment(9, 1, 1, true), Segments[3]);568  EXPECT_EQ(CoverageSegment(11, 13, 2, true), Segments[4]);569  // Use count=1 (from 9:1 -> 14:6), not count=0 (from 8:12 -> 14:6).570  EXPECT_EQ(CoverageSegment(11, 14, 1, false), Segments[5]);571  EXPECT_EQ(CoverageSegment(18, 2, false), Segments[6]);572}573 574TEST_P(CoverageMappingTest, dont_emit_redundant_segments) {575  ProfileWriter.addRecord({"func1", 0x1234, {1, 1}}, Err);576  startFunction("func1", 0x1234);577 578  addCMR(Counter::getCounter(0), "file1", 1, 1, 4, 4);579  addCMR(Counter::getCounter(1), "file1", 2, 2, 5, 5);580  addCMR(Counter::getCounter(0), "file1", 3, 3, 6, 6);581 582  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());583  const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();584  const auto &FunctionRecord = *FunctionRecords.begin();585  CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);586  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());587 588  ASSERT_EQ(5U, Segments.size());589  EXPECT_EQ(CoverageSegment(1, 1, 1, true), Segments[0]);590  EXPECT_EQ(CoverageSegment(2, 2, 1, true), Segments[1]);591  EXPECT_EQ(CoverageSegment(3, 3, 1, true), Segments[2]);592  EXPECT_EQ(CoverageSegment(4, 4, 1, false), Segments[3]);593  // A closing segment starting at 5:5 would be redundant: it would have the594  // same count as the segment starting at 4:4, and has all the same metadata.595  EXPECT_EQ(CoverageSegment(6, 6, false), Segments[4]);596}597 598TEST_P(CoverageMappingTest, dont_emit_closing_segment_at_new_region_start) {599  ProfileWriter.addRecord({"func1", 0x1234, {1}}, Err);600  startFunction("func1", 0x1234);601 602  addCMR(Counter::getCounter(0), "file1", 1, 1, 6, 5);603  addCMR(Counter::getCounter(0), "file1", 2, 2, 6, 5);604  addCMR(Counter::getCounter(0), "file1", 3, 3, 6, 5);605  addCMR(Counter::getCounter(0), "file1", 6, 5, 7, 7);606 607  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());608  const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();609  const auto &FunctionRecord = *FunctionRecords.begin();610  CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);611  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());612 613  ASSERT_EQ(5U, Segments.size());614  EXPECT_EQ(CoverageSegment(1, 1, 1, true), Segments[0]);615  EXPECT_EQ(CoverageSegment(2, 2, 1, true), Segments[1]);616  EXPECT_EQ(CoverageSegment(3, 3, 1, true), Segments[2]);617  EXPECT_EQ(CoverageSegment(6, 5, 1, true), Segments[3]);618  // The old segment builder would get this wrong by emitting multiple segments619  // which start at 6:5 (a few of which were skipped segments). We should just620  // get a segment for the region entry.621  EXPECT_EQ(CoverageSegment(7, 7, false), Segments[4]);622}623 624TEST_P(CoverageMappingTest, handle_consecutive_regions_with_zero_length) {625  ProfileWriter.addRecord({"func1", 0x1234, {1, 2}}, Err);626  startFunction("func1", 0x1234);627 628  addCMR(Counter::getCounter(0), "file1", 1, 1, 1, 1);629  addCMR(Counter::getCounter(1), "file1", 1, 1, 1, 1);630  addCMR(Counter::getCounter(0), "file1", 1, 1, 1, 1);631  addCMR(Counter::getCounter(1), "file1", 1, 1, 1, 1);632  addCMR(Counter::getCounter(0), "file1", 1, 1, 1, 1);633 634  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());635  const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();636  const auto &FunctionRecord = *FunctionRecords.begin();637  CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);638  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());639 640  ASSERT_EQ(1U, Segments.size());641  EXPECT_EQ(CoverageSegment(1, 1, true), Segments[0]);642  // We need to get a skipped segment starting at 1:1. In this case there is643  // also a region entry at 1:1.644}645 646TEST_P(CoverageMappingTest, handle_sandwiched_zero_length_region) {647  ProfileWriter.addRecord({"func1", 0x1234, {2, 1}}, Err);648  startFunction("func1", 0x1234);649 650  addCMR(Counter::getCounter(0), "file1", 1, 5, 4, 4);651  addCMR(Counter::getCounter(1), "file1", 1, 9, 1, 50);652  addCMR(Counter::getCounter(1), "file1", 2, 7, 2, 34);653  addCMR(Counter::getCounter(1), "file1", 3, 5, 3, 21);654  addCMR(Counter::getCounter(1), "file1", 3, 21, 3, 21);655  addCMR(Counter::getCounter(1), "file1", 4, 12, 4, 17);656 657  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());658  const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();659  const auto &FunctionRecord = *FunctionRecords.begin();660  CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);661  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());662 663  ASSERT_EQ(10U, Segments.size());664  EXPECT_EQ(CoverageSegment(1, 5, 2, true), Segments[0]);665  EXPECT_EQ(CoverageSegment(1, 9, 1, true), Segments[1]);666  EXPECT_EQ(CoverageSegment(1, 50, 2, false), Segments[2]);667  EXPECT_EQ(CoverageSegment(2, 7, 1, true), Segments[3]);668  EXPECT_EQ(CoverageSegment(2, 34, 2, false), Segments[4]);669  EXPECT_EQ(CoverageSegment(3, 5, 1, true), Segments[5]);670  EXPECT_EQ(CoverageSegment(3, 21, 2, true), Segments[6]);671  // Handle the zero-length region by creating a segment with its predecessor's672  // count (i.e the count from 1:5 -> 4:4).673  EXPECT_EQ(CoverageSegment(4, 4, false), Segments[7]);674  // The area between 4:4 and 4:12 is skipped.675  EXPECT_EQ(CoverageSegment(4, 12, 1, true), Segments[8]);676  EXPECT_EQ(CoverageSegment(4, 17, false), Segments[9]);677}678 679TEST_P(CoverageMappingTest, handle_last_completed_region) {680  ProfileWriter.addRecord({"func1", 0x1234, {1, 2, 3, 4}}, Err);681  startFunction("func1", 0x1234);682 683  addCMR(Counter::getCounter(0), "file1", 1, 1, 8, 8);684  addCMR(Counter::getCounter(1), "file1", 2, 2, 5, 5);685  addCMR(Counter::getCounter(2), "file1", 3, 3, 4, 4);686  addCMR(Counter::getCounter(3), "file1", 6, 6, 7, 7);687 688  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());689  const auto FunctionRecords = LoadedCoverage->getCoveredFunctions();690  const auto &FunctionRecord = *FunctionRecords.begin();691  CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord);692  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());693 694  ASSERT_EQ(8U, Segments.size());695  EXPECT_EQ(CoverageSegment(1, 1, 1, true), Segments[0]);696  EXPECT_EQ(CoverageSegment(2, 2, 2, true), Segments[1]);697  EXPECT_EQ(CoverageSegment(3, 3, 3, true), Segments[2]);698  EXPECT_EQ(CoverageSegment(4, 4, 2, false), Segments[3]);699  EXPECT_EQ(CoverageSegment(5, 5, 1, false), Segments[4]);700  EXPECT_EQ(CoverageSegment(6, 6, 4, true), Segments[5]);701  EXPECT_EQ(CoverageSegment(7, 7, 1, false), Segments[6]);702  EXPECT_EQ(CoverageSegment(8, 8, false), Segments[7]);703}704 705TEST_P(CoverageMappingTest, expansion_gets_first_counter) {706  startFunction("func", 0x1234);707  addCMR(Counter::getCounter(1), "foo", 10, 1, 10, 2);708  // This starts earlier in "foo", so the expansion should get its counter.709  addCMR(Counter::getCounter(2), "foo", 1, 1, 20, 1);710  addExpansionCMR("bar", "foo", 3, 3, 3, 3);711 712  writeAndReadCoverageRegions();713  ASSERT_EQ(1u, OutputFunctions.size());714  OutputFunctionCoverageData &Output = OutputFunctions.back();715 716  ASSERT_EQ(CounterMappingRegion::ExpansionRegion, Output.Regions[2].Kind);717  ASSERT_EQ(Counter::getCounter(2), Output.Regions[2].Count);718  ASSERT_EQ(3U, Output.Regions[2].LineStart);719}720 721TEST_P(CoverageMappingTest, basic_coverage_iteration) {722  ProfileWriter.addRecord({"func", 0x1234, {30, 20, 10, 0}}, Err);723 724  startFunction("func", 0x1234);725  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);726  addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7);727  addCMR(Counter::getCounter(2), "file1", 5, 8, 9, 1);728  addCMR(Counter::getCounter(3), "file1", 10, 10, 11, 11);729  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());730 731  CoverageData Data = LoadedCoverage->getCoverageForFile("file1");732  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());733  ASSERT_EQ(7U, Segments.size());734  ASSERT_EQ(CoverageSegment(1, 1, 20, true),  Segments[0]);735  ASSERT_EQ(CoverageSegment(4, 7, 30, false), Segments[1]);736  ASSERT_EQ(CoverageSegment(5, 8, 10, true),  Segments[2]);737  ASSERT_EQ(CoverageSegment(9, 1, 30, false), Segments[3]);738  ASSERT_EQ(CoverageSegment(9, 9, false),     Segments[4]);739  ASSERT_EQ(CoverageSegment(10, 10, 0, true), Segments[5]);740  ASSERT_EQ(CoverageSegment(11, 11, false),   Segments[6]);741}742 743TEST_P(CoverageMappingTest, test_line_coverage_iterator) {744  ProfileWriter.addRecord({"func", 0x1234, {30, 20, 10, 0}}, Err);745 746  startFunction("func", 0x1234);747  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);748  addSkipped("file1", 1, 3, 1, 8); // skipped region inside previous block749  addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7);750  addSkipped("file1", 4, 1, 4, 20); // skipped line751  addCMR(Counter::getCounter(2), "file1", 5, 8, 9, 1);752  addSkipped("file1", 10, 1, 12,753             20); // skipped region which contains next region754  addCMR(Counter::getCounter(3), "file1", 10, 10, 11, 11);755  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());756  CoverageData Data = LoadedCoverage->getCoverageForFile("file1");757 758  unsigned Line = 0;759  const unsigned LineCounts[] = {20, 20, 20, 0, 30, 10, 10, 10, 10, 0, 0, 0, 0};760  const bool MappedLines[] = {1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0};761  ASSERT_EQ(std::size(LineCounts), std::size(MappedLines));762 763  for (const auto &LCS : getLineCoverageStats(Data)) {764    ASSERT_LT(Line, std::size(LineCounts));765    ASSERT_LT(Line, std::size(MappedLines));766 767    ASSERT_EQ(Line + 1, LCS.getLine());768    errs() << "Line: " << Line + 1 << ", count = " << LCS.getExecutionCount()769           << ", mapped = " << LCS.isMapped() << "\n";770    ASSERT_EQ(LineCounts[Line], LCS.getExecutionCount());771    ASSERT_EQ(MappedLines[Line], LCS.isMapped());772    ++Line;773  }774  ASSERT_EQ(12U, Line);775 776  // Check that operator->() works / compiles.777  ASSERT_EQ(1U, LineCoverageIterator(Data)->getLine());778}779 780TEST_P(CoverageMappingTest, uncovered_function) {781  startFunction("func", 0x1234);782  addCMR(Counter::getZero(), "file1", 1, 2, 3, 4);783  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());784 785  CoverageData Data = LoadedCoverage->getCoverageForFile("file1");786  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());787  ASSERT_EQ(2U, Segments.size());788  ASSERT_EQ(CoverageSegment(1, 2, 0, true), Segments[0]);789  ASSERT_EQ(CoverageSegment(3, 4, false),   Segments[1]);790}791 792TEST_P(CoverageMappingTest, uncovered_function_with_mapping) {793  startFunction("func", 0x1234);794  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);795  addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7);796  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());797 798  CoverageData Data = LoadedCoverage->getCoverageForFile("file1");799  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());800  ASSERT_EQ(3U, Segments.size());801  ASSERT_EQ(CoverageSegment(1, 1, 0, true),  Segments[0]);802  ASSERT_EQ(CoverageSegment(4, 7, 0, false), Segments[1]);803  ASSERT_EQ(CoverageSegment(9, 9, false),    Segments[2]);804}805 806TEST_P(CoverageMappingTest, combine_regions) {807  ProfileWriter.addRecord({"func", 0x1234, {10, 20, 30}}, Err);808 809  startFunction("func", 0x1234);810  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);811  addCMR(Counter::getCounter(1), "file1", 3, 3, 4, 4);812  addCMR(Counter::getCounter(2), "file1", 3, 3, 4, 4);813  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());814 815  CoverageData Data = LoadedCoverage->getCoverageForFile("file1");816  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());817  ASSERT_EQ(4U, Segments.size());818  ASSERT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]);819  ASSERT_EQ(CoverageSegment(3, 3, 50, true), Segments[1]);820  ASSERT_EQ(CoverageSegment(4, 4, 10, false), Segments[2]);821  ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]);822}823 824TEST_P(CoverageMappingTest, restore_combined_counter_after_nested_region) {825  ProfileWriter.addRecord({"func", 0x1234, {10, 20, 40}}, Err);826 827  startFunction("func", 0x1234);828  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);829  addCMR(Counter::getCounter(1), "file1", 1, 1, 9, 9);830  addCMR(Counter::getCounter(2), "file1", 3, 3, 5, 5);831  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());832 833  CoverageData Data = LoadedCoverage->getCoverageForFile("file1");834  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());835  ASSERT_EQ(4U, Segments.size());836  EXPECT_EQ(CoverageSegment(1, 1, 30, true), Segments[0]);837  EXPECT_EQ(CoverageSegment(3, 3, 40, true), Segments[1]);838  EXPECT_EQ(CoverageSegment(5, 5, 30, false), Segments[2]);839  EXPECT_EQ(CoverageSegment(9, 9, false), Segments[3]);840}841 842// If CodeRegions and ExpansionRegions cover the same area,843// only counts of CodeRegions should be used.844TEST_P(CoverageMappingTest, dont_combine_expansions) {845  ProfileWriter.addRecord({"func", 0x1234, {10, 20}}, Err);846  ProfileWriter.addRecord({"func", 0x1234, {0, 0}}, Err);847 848  startFunction("func", 0x1234);849  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);850  addCMR(Counter::getCounter(1), "file1", 3, 3, 4, 4);851  addCMR(Counter::getCounter(1), "include1", 6, 6, 7, 7);852  addExpansionCMR("file1", "include1", 3, 3, 4, 4);853  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());854 855  CoverageData Data = LoadedCoverage->getCoverageForFile("file1");856  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());857  ASSERT_EQ(4U, Segments.size());858  ASSERT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]);859  ASSERT_EQ(CoverageSegment(3, 3, 20, true), Segments[1]);860  ASSERT_EQ(CoverageSegment(4, 4, 10, false), Segments[2]);861  ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]);862}863 864// If an area is covered only by ExpansionRegions, they should be combinated.865TEST_P(CoverageMappingTest, combine_expansions) {866  ProfileWriter.addRecord({"func", 0x1234, {2, 3, 7}}, Err);867 868  startFunction("func", 0x1234);869  addCMR(Counter::getCounter(1), "include1", 1, 1, 1, 10);870  addCMR(Counter::getCounter(2), "include2", 1, 1, 1, 10);871  addCMR(Counter::getCounter(0), "file", 1, 1, 5, 5);872  addExpansionCMR("file", "include1", 3, 1, 3, 5);873  addExpansionCMR("file", "include2", 3, 1, 3, 5);874 875  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());876 877  CoverageData Data = LoadedCoverage->getCoverageForFile("file");878  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());879  ASSERT_EQ(4U, Segments.size());880  EXPECT_EQ(CoverageSegment(1, 1, 2, true), Segments[0]);881  EXPECT_EQ(CoverageSegment(3, 1, 10, true), Segments[1]);882  EXPECT_EQ(CoverageSegment(3, 5, 2, false), Segments[2]);883  EXPECT_EQ(CoverageSegment(5, 5, false), Segments[3]);884}885 886// Test that counters not associated with any code regions are allowed.887TEST_P(CoverageMappingTest, non_code_region_counters) {888  // No records in profdata889 890  startFunction("func", 0x1234);891  addCMR(Counter::getCounter(0), "file", 1, 1, 5, 5);892  addCMR(Counter::getExpression(0), "file", 6, 1, 6, 5);893  addExpression(CounterExpression(894      CounterExpression::Add, Counter::getCounter(1), Counter::getCounter(2)));895 896  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());897 898  std::vector<std::string> Names;899  for (const auto &Func : LoadedCoverage->getCoveredFunctions()) {900    Names.push_back(Func.Name);901    ASSERT_EQ(2U, Func.CountedRegions.size());902  }903  ASSERT_EQ(1U, Names.size());904}905 906// Test that MCDC bitmasks not associated with any code regions are allowed.907TEST_P(CoverageMappingTest, non_code_region_bitmask) {908  // No records in profdata909 910  startFunction("func", 0x1234);911  addCMR(Counter::getCounter(0), "file", 1, 1, 5, 5);912  addCMR(Counter::getCounter(1), "file", 1, 1, 5, 5);913  addCMR(Counter::getCounter(2), "file", 1, 1, 5, 5);914  addCMR(Counter::getCounter(3), "file", 1, 1, 5, 5);915 916  addMCDCDecisionCMR(3, 2, "file", 7, 1, 7, 6);917  addMCDCBranchCMR(Counter::getCounter(0), Counter::getCounter(1), 0, {-1, 1},918                   "file", 7, 2, 7, 3);919  addMCDCBranchCMR(Counter::getCounter(2), Counter::getCounter(3), 1, {-1, -1},920                   "file", 7, 4, 7, 5);921 922  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());923 924  std::vector<std::string> Names;925  for (const auto &Func : LoadedCoverage->getCoveredFunctions()) {926    Names.push_back(Func.Name);927    ASSERT_EQ(2U, Func.CountedBranchRegions.size());928    ASSERT_EQ(1U, Func.MCDCRecords.size());929  }930  ASSERT_EQ(1U, Names.size());931}932 933// Test the order of MCDCDecision before Expansion934TEST_P(CoverageMappingTest, decision_before_expansion) {935  startFunction("foo", 0x1234);936  addCMR(Counter::getCounter(0), "foo", 3, 23, 5, 2);937 938  // This(4:11) was put after Expansion(4:11) before the fix939  addMCDCDecisionCMR(3, 2, "foo", 4, 11, 4, 20);940 941  addExpansionCMR("foo", "A", 4, 11, 4, 12);942  addExpansionCMR("foo", "B", 4, 19, 4, 20);943  addCMR(Counter::getCounter(0), "A", 1, 14, 1, 17);944  addCMR(Counter::getCounter(0), "A", 1, 14, 1, 17);945  addMCDCBranchCMR(Counter::getCounter(0), Counter::getCounter(1), 0, {-1, 1},946                   "A", 1, 14, 1, 17);947  addCMR(Counter::getCounter(1), "B", 1, 14, 1, 17);948  addMCDCBranchCMR(Counter::getCounter(1), Counter::getCounter(2), 1, {-1, -1},949                   "B", 1, 14, 1, 17);950 951  // InputFunctionCoverageData::Regions is rewritten after the write.952  auto InputRegions = InputFunctions.back().Regions;953 954  writeAndReadCoverageRegions();955 956  const auto &OutputRegions = OutputFunctions.back().Regions;957 958  size_t N = ArrayRef(InputRegions).size();959  ASSERT_EQ(N, OutputRegions.size());960  for (size_t I = 0; I < N; ++I) {961    ASSERT_EQ(InputRegions[I].Kind, OutputRegions[I].Kind);962    ASSERT_EQ(InputRegions[I].FileID, OutputRegions[I].FileID);963    ASSERT_EQ(InputRegions[I].ExpandedFileID, OutputRegions[I].ExpandedFileID);964    ASSERT_EQ(InputRegions[I].startLoc(), OutputRegions[I].startLoc());965    ASSERT_EQ(InputRegions[I].endLoc(), OutputRegions[I].endLoc());966  }967}968 969TEST_P(CoverageMappingTest, strip_filename_prefix) {970  ProfileWriter.addRecord({"file1:func", 0x1234, {0}}, Err);971 972  startFunction("file1:func", 0x1234);973  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);974  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());975 976  std::vector<std::string> Names;977  for (const auto &Func : LoadedCoverage->getCoveredFunctions())978    Names.push_back(Func.Name);979  ASSERT_EQ(1U, Names.size());980  ASSERT_EQ("func", Names[0]);981}982 983TEST_P(CoverageMappingTest, strip_unknown_filename_prefix) {984  ProfileWriter.addRecord({"<unknown>:func", 0x1234, {0}}, Err);985 986  startFunction("<unknown>:func", 0x1234);987  addCMR(Counter::getCounter(0), "", 1, 1, 9, 9);988  EXPECT_THAT_ERROR(loadCoverageMapping(/*EmitFilenames=*/false), Succeeded());989 990  std::vector<std::string> Names;991  for (const auto &Func : LoadedCoverage->getCoveredFunctions())992    Names.push_back(Func.Name);993  ASSERT_EQ(1U, Names.size());994  ASSERT_EQ("func", Names[0]);995}996 997TEST_P(CoverageMappingTest, dont_detect_false_instantiations) {998  ProfileWriter.addRecord({"foo", 0x1234, {10}}, Err);999  ProfileWriter.addRecord({"bar", 0x2345, {20}}, Err);1000 1001  startFunction("foo", 0x1234);1002  addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10);1003  addExpansionCMR("main", "expanded", 4, 1, 4, 5);1004 1005  startFunction("bar", 0x2345);1006  addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10);1007  addExpansionCMR("main", "expanded", 9, 1, 9, 5);1008 1009  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());1010 1011  std::vector<InstantiationGroup> InstantiationGroups =1012      LoadedCoverage->getInstantiationGroups("expanded");1013  ASSERT_TRUE(InstantiationGroups.empty());1014}1015 1016TEST_P(CoverageMappingTest, load_coverage_for_expanded_file) {1017  ProfileWriter.addRecord({"func", 0x1234, {10}}, Err);1018 1019  startFunction("func", 0x1234);1020  addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10);1021  addExpansionCMR("main", "expanded", 4, 1, 4, 5);1022 1023  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());1024 1025  CoverageData Data = LoadedCoverage->getCoverageForFile("expanded");1026  std::vector<CoverageSegment> Segments(Data.begin(), Data.end());1027  ASSERT_EQ(2U, Segments.size());1028  EXPECT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]);1029  EXPECT_EQ(CoverageSegment(1, 10, false), Segments[1]);1030}1031 1032TEST_P(CoverageMappingTest, skip_duplicate_function_record) {1033  ProfileWriter.addRecord({"func", 0x1234, {1}}, Err);1034 1035  // This record should be loaded.1036  startFunction("func", 0x1234);1037  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);1038 1039  // This record should be loaded.1040  startFunction("func", 0x1234);1041  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);1042  addCMR(Counter::getCounter(0), "file2", 1, 1, 9, 9);1043 1044  // This record should be skipped.1045  startFunction("func", 0x1234);1046  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);1047 1048  // This record should be loaded.1049  startFunction("func", 0x1234);1050  addCMR(Counter::getCounter(0), "file2", 1, 1, 9, 9);1051  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);1052 1053  // This record should be skipped.1054  startFunction("func", 0x1234);1055  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);1056  addCMR(Counter::getCounter(0), "file2", 1, 1, 9, 9);1057 1058  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());1059 1060  auto Funcs = LoadedCoverage->getCoveredFunctions();1061  unsigned NumFuncs = std::distance(Funcs.begin(), Funcs.end());1062  ASSERT_EQ(3U, NumFuncs);1063}1064 1065INSTANTIATE_TEST_SUITE_P(ParameterizedCovMapTest, CoverageMappingTest,1066                         ::testing::Combine(::testing::Bool(),1067                                            ::testing::Bool()));1068 1069TEST(CoverageMappingTest, filename_roundtrip) {1070  std::vector<std::string> Paths({"dir", "a", "b", "c", "d", "e"});1071 1072  for (bool Compress : {false, true}) {1073    std::string EncodedFilenames;1074    {1075      raw_string_ostream OS(EncodedFilenames);1076      CoverageFilenamesSectionWriter Writer(Paths);1077      Writer.write(OS, Compress);1078    }1079 1080    std::vector<std::string> ReadFilenames;1081    RawCoverageFilenamesReader Reader(EncodedFilenames, ReadFilenames);1082    EXPECT_THAT_ERROR(Reader.read(CovMapVersion::CurrentVersion), Succeeded());1083 1084    ASSERT_EQ(ReadFilenames.size(), Paths.size());1085    for (unsigned I = 1; I < Paths.size(); ++I) {1086      SmallString<256> P(Paths[0]);1087      llvm::sys::path::append(P, Paths[I]);1088      ASSERT_EQ(ReadFilenames[I], P);1089    }1090  }1091}1092 1093TEST(CoverageMappingTest, filename_compilation_dir) {1094  std::vector<std::string> Paths({"dir", "a", "b", "c", "d", "e"});1095 1096  for (bool Compress : {false, true}) {1097    std::string EncodedFilenames;1098    {1099      raw_string_ostream OS(EncodedFilenames);1100      CoverageFilenamesSectionWriter Writer(Paths);1101      Writer.write(OS, Compress);1102    }1103 1104    StringRef CompilationDir = "out";1105    std::vector<std::string> ReadFilenames;1106    RawCoverageFilenamesReader Reader(EncodedFilenames, ReadFilenames,1107                                      CompilationDir);1108    EXPECT_THAT_ERROR(Reader.read(CovMapVersion::CurrentVersion), Succeeded());1109 1110    ASSERT_EQ(ReadFilenames.size(), Paths.size());1111    for (unsigned I = 1; I < Paths.size(); ++I) {1112      SmallString<256> P(CompilationDir);1113      llvm::sys::path::append(P, Paths[I]);1114      ASSERT_EQ(ReadFilenames[I], P);1115    }1116  }1117}1118 1119TEST(CoverageMappingTest, TVIdxBuilder) {1120  // ((n0 && n3) || (n2 && n4) || (n1 && n5))1121  static const std::array<mcdc::ConditionIDs, 6> Branches = {{1122      {2, 3},1123      {-1, 5},1124      {1, 4},1125      {2, -1},1126      {1, -1},1127      {-1, -1},1128  }};1129  int Offset = 1000;1130  auto TheBuilder = mcdc::TVIdxBuilder(1131      SmallVector<mcdc::ConditionIDs>(ArrayRef(Branches)), Offset);1132  EXPECT_TRUE(TheBuilder.NumTestVectors < TheBuilder.HardMaxTVs);1133  EXPECT_EQ(TheBuilder.Indices.size(), 6u);1134  EXPECT_EQ(TheBuilder.NumTestVectors, 15);1135 1136  std::map<int, int> Decisions;1137  for (unsigned I = 0; I < TheBuilder.Indices.size(); ++I) {1138    struct Rec {1139      int Width;1140      std::array<int, 2> Indices;1141    };1142    static const std::array<Rec, 6> IndicesRefs = {{1143        {1, {0, 0}},1144        {4, {1000, 0}},1145        {2, {0, 0}},1146        {1, {1, 1014}},1147        {2, {2, 1012}},1148        {4, {1004, 1008}},1149    }};1150    EXPECT_EQ(TheBuilder.Indices[I], IndicesRefs[I].Indices);1151 1152#ifndef NDEBUG1153    const auto &Node = TheBuilder.SavedNodes[I];1154    EXPECT_EQ(Node.Width, IndicesRefs[I].Width);1155    for (int C = 0; C < 2; ++C) {1156      auto Index = TheBuilder.Indices[I][C];1157      if (Node.NextIDs[C] < 0)1158        EXPECT_TRUE(Decisions.insert({Index, Node.Width}).second);1159    }1160#endif1161  }1162 1163#ifndef NDEBUG1164  int NextIdx = Offset;1165  for (const auto [Index, Width] : Decisions) {1166    EXPECT_EQ(Index, NextIdx);1167    NextIdx += Width;1168  }1169  // The sum of Width(s) is NumTVs.1170  EXPECT_EQ(NextIdx, Offset + TheBuilder.NumTestVectors);1171#endif1172}1173 1174} // end anonymous namespace1175