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