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