1 //===-- TextStubV5Tests.cpp - TBD V5 File Test ----------------------------===// 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 "TextStubHelpers.h" 10 #include "llvm/TextAPI/InterfaceFile.h" 11 #include "llvm/TextAPI/TextAPIReader.h" 12 #include "llvm/TextAPI/TextAPIWriter.h" 13 #include "gtest/gtest.h" 14 #include <string> 15 #include <vector> 16 17 using namespace llvm; 18 using namespace llvm::MachO; 19 20 namespace TBDv5 { 21 22 TEST(TBDv5, ReadFile) { 23 static const char TBDv5File[] = R"({ 24 "tapi_tbd_version": 5, 25 "main_library": { 26 "target_info": [ 27 { 28 "target": "x86_64-macos", 29 "min_deployment": "10.14" 30 }, 31 { 32 "target": "arm64-macos", 33 "min_deployment": "10.14" 34 }, 35 { 36 "target": "arm64-maccatalyst", 37 "min_deployment": "12.1" 38 } 39 ], 40 "flags": [ 41 { 42 "targets": [ 43 "x86_64-macos" 44 ], 45 "attributes": [ 46 "flat_namespace" 47 ] 48 } 49 ], 50 "install_names": [ 51 { 52 "name": "/S/L/F/Foo.framework/Foo" 53 } 54 ], 55 "current_versions": [ 56 { 57 "version": "1.2" 58 } 59 ], 60 "compatibility_versions": [ 61 { "version": "1.1" } 62 ], 63 "rpaths": [ 64 { 65 "targets": [ 66 "x86_64-macos" 67 ], 68 "paths": [ 69 "@executable_path/.../Frameworks" 70 ] 71 } 72 ], 73 "parent_umbrellas": [ 74 { 75 "umbrella": "System" 76 } 77 ], 78 "allowable_clients": [ 79 { 80 "clients": [ 81 "ClientA", 82 "ClientB" 83 ] 84 } 85 ], 86 "reexported_libraries": [ 87 { 88 "names": [ 89 "/u/l/l/libfoo.dylib", 90 "/u/l/l/libbar.dylib" 91 ] 92 } 93 ], 94 "exported_symbols": [ 95 { 96 "targets": [ 97 "x86_64-macos", 98 "arm64-macos" 99 ], 100 "data": { 101 "global": [ 102 "_global" 103 ], 104 "objc_class": [ 105 "ClassA" 106 ], 107 "weak": [], 108 "thread_local": [] 109 }, 110 "text": { 111 "global": [ 112 "_func" 113 ], 114 "weak": [], 115 "thread_local": [] 116 } 117 }, 118 { 119 "targets": [ 120 "x86_64-macos" 121 ], 122 "data": { 123 "global": [ 124 "_globalVar" 125 ], 126 "objc_class": [ 127 "ClassData" 128 ], 129 "objc_eh_type": [ 130 "ClassA", 131 "ClassB" 132 ], 133 "objc_ivar": [ 134 "ClassA.ivar1", 135 "ClassA.ivar2", 136 "ClassC.ivar1" 137 ] 138 }, 139 "text": { 140 "global": [ 141 "_funcFoo" 142 ] 143 } 144 } 145 ], 146 "reexported_symbols": [ 147 { 148 "targets": [ 149 "x86_64-macos", 150 "arm64-macos" 151 ], 152 "data": { 153 "global": [ 154 "_globalRe" 155 ], 156 "objc_class": [ 157 "ClassRexport" 158 ] 159 }, 160 "text": { 161 "global": [ 162 "_funcA" 163 ] 164 } 165 } 166 ], 167 "undefined_symbols": [ 168 { 169 "targets": [ 170 "x86_64-macos" 171 ], 172 "data": { 173 "global": [ 174 "_globalBind" 175 ], 176 "weak": [ 177 "referenced_sym" 178 ] 179 } 180 } 181 ] 182 }, 183 "libraries": [] 184 })"; 185 186 Expected<TBDFile> Result = 187 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd")); 188 EXPECT_TRUE(!!Result); 189 TBDFile File = std::move(Result.get()); 190 EXPECT_EQ(FileType::TBD_V5, File->getFileType()); 191 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName()); 192 193 TargetList AllTargets = { 194 Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)), 195 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)), 196 Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)), 197 }; 198 EXPECT_EQ(mapToPlatformSet(AllTargets), File->getPlatforms()); 199 EXPECT_EQ(mapToArchitectureSet(AllTargets), File->getArchitectures()); 200 201 EXPECT_EQ(PackedVersion(1, 2, 0), File->getCurrentVersion()); 202 EXPECT_EQ(PackedVersion(1, 1, 0), File->getCompatibilityVersion()); 203 EXPECT_TRUE(File->isApplicationExtensionSafe()); 204 EXPECT_FALSE(File->isTwoLevelNamespace()); 205 EXPECT_EQ(0U, File->documents().size()); 206 207 InterfaceFileRef ClientA("ClientA", AllTargets); 208 InterfaceFileRef ClientB("ClientB", AllTargets); 209 EXPECT_EQ(2U, File->allowableClients().size()); 210 EXPECT_EQ(ClientA, File->allowableClients().at(0)); 211 EXPECT_EQ(ClientB, File->allowableClients().at(1)); 212 213 InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets); 214 InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets); 215 EXPECT_EQ(2U, File->reexportedLibraries().size()); 216 EXPECT_EQ(ReexportA, File->reexportedLibraries().at(0)); 217 EXPECT_EQ(ReexportB, File->reexportedLibraries().at(1)); 218 219 TargetToAttr RPaths = { 220 {Target(AK_x86_64, PLATFORM_MACOS), "@executable_path/.../Frameworks"}, 221 }; 222 EXPECT_EQ(RPaths, File->rpaths()); 223 224 TargetToAttr Umbrellas = {{Target(AK_x86_64, PLATFORM_MACOS), "System"}, 225 {Target(AK_arm64, PLATFORM_MACOS), "System"}, 226 {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}}; 227 EXPECT_EQ(Umbrellas, File->umbrellas()); 228 229 ExportedSymbolSeq Exports, Reexports, Undefineds; 230 for (const auto *Sym : File->symbols()) { 231 TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()}; 232 ExportedSymbol Temp = 233 ExportedSymbol{Sym->getKind(), 234 std::string(Sym->getName()), 235 Sym->isWeakDefined() || Sym->isWeakReferenced(), 236 Sym->isThreadLocalValue(), 237 Sym->isData(), 238 SymTargets}; 239 if (Sym->isUndefined()) 240 Undefineds.emplace_back(std::move(Temp)); 241 else 242 Sym->isReexported() ? Reexports.emplace_back(std::move(Temp)) 243 : Exports.emplace_back(std::move(Temp)); 244 } 245 llvm::sort(Exports); 246 llvm::sort(Reexports); 247 llvm::sort(Undefineds); 248 249 TargetList MacOSTargets = {Target(AK_x86_64, PLATFORM_MACOS), 250 Target(AK_arm64, PLATFORM_MACOS)}; 251 252 std::vector<ExportedSymbol> ExpectedExportedSymbols = { 253 {SymbolKind::GlobalSymbol, "_func", false, false, false, MacOSTargets}, 254 {SymbolKind::GlobalSymbol, 255 "_funcFoo", 256 false, 257 false, 258 false, 259 {Target(AK_x86_64, PLATFORM_MACOS)}}, 260 {SymbolKind::GlobalSymbol, "_global", false, false, true, MacOSTargets}, 261 {SymbolKind::GlobalSymbol, 262 "_globalVar", 263 false, 264 false, 265 true, 266 {Target(AK_x86_64, PLATFORM_MACOS)}}, 267 {SymbolKind::ObjectiveCClass, "ClassA", false, false, true, MacOSTargets}, 268 {SymbolKind::ObjectiveCClass, 269 "ClassData", 270 false, 271 false, 272 true, 273 {Target(AK_x86_64, PLATFORM_MACOS)}}, 274 {SymbolKind::ObjectiveCClassEHType, 275 "ClassA", 276 false, 277 false, 278 true, 279 {Target(AK_x86_64, PLATFORM_MACOS)}}, 280 {SymbolKind::ObjectiveCClassEHType, 281 "ClassB", 282 false, 283 false, 284 true, 285 {Target(AK_x86_64, PLATFORM_MACOS)}}, 286 {SymbolKind::ObjectiveCInstanceVariable, 287 "ClassA.ivar1", 288 false, 289 false, 290 true, 291 {Target(AK_x86_64, PLATFORM_MACOS)}}, 292 {SymbolKind::ObjectiveCInstanceVariable, 293 "ClassA.ivar2", 294 false, 295 false, 296 true, 297 {Target(AK_x86_64, PLATFORM_MACOS)}}, 298 {SymbolKind::ObjectiveCInstanceVariable, 299 "ClassC.ivar1", 300 false, 301 false, 302 true, 303 {Target(AK_x86_64, PLATFORM_MACOS)}}, 304 }; 305 std::vector<ExportedSymbol> ExpectedReexportedSymbols = { 306 {SymbolKind::GlobalSymbol, "_funcA", false, false, false, MacOSTargets}, 307 {SymbolKind::GlobalSymbol, "_globalRe", false, false, true, MacOSTargets}, 308 {SymbolKind::ObjectiveCClass, "ClassRexport", false, false, true, 309 MacOSTargets}, 310 }; 311 312 std::vector<ExportedSymbol> ExpectedUndefinedSymbols = { 313 {SymbolKind::GlobalSymbol, 314 "_globalBind", 315 false, 316 false, 317 true, 318 {Target(AK_x86_64, PLATFORM_MACOS)}}, 319 {SymbolKind::GlobalSymbol, 320 "referenced_sym", 321 true, 322 false, 323 true, 324 {Target(AK_x86_64, PLATFORM_MACOS)}}, 325 }; 326 327 EXPECT_EQ(ExpectedExportedSymbols.size(), Exports.size()); 328 EXPECT_EQ(ExpectedReexportedSymbols.size(), Reexports.size()); 329 EXPECT_EQ(ExpectedUndefinedSymbols.size(), Undefineds.size()); 330 EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(), 331 std::begin(ExpectedExportedSymbols))); 332 EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(), 333 std::begin(ExpectedReexportedSymbols))); 334 EXPECT_TRUE(std::equal(Undefineds.begin(), Undefineds.end(), 335 std::begin(ExpectedUndefinedSymbols))); 336 } 337 338 TEST(TBDv5, ReadMultipleTargets) { 339 static const char TBDv5File[] = R"({ 340 "tapi_tbd_version": 5, 341 "main_library": { 342 "target_info": [ 343 { 344 "target": "x86_64-macos", 345 "min_deployment": "10.14" 346 }, 347 { 348 "target": "arm64-macos", 349 "min_deployment": "10.14" 350 }, 351 { 352 "target": "arm64-maccatalyst", 353 "min_deployment": "12.1" 354 } 355 ], 356 "install_names":[ 357 { "name":"/usr/lib/libFoo.dylib" } 358 ], 359 "swift_abi":[ { "abi":8 } ], 360 "reexported_libraries": [ 361 { 362 "targets": [ "x86_64-maccatalyst" ], 363 "names": [ 364 "/u/l/l/libfoo.dylib", 365 "/u/l/l/libbar.dylib" 366 ] 367 }, 368 { 369 "targets": [ "arm64-maccatalyst" ], 370 "names": [ "/u/l/l/libArmOnly.dylib" ] 371 } 372 ] 373 } 374 })"; 375 376 Expected<TBDFile> Result = 377 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd")); 378 EXPECT_TRUE(!!Result); 379 TBDFile File = std::move(Result.get()); 380 EXPECT_EQ(FileType::TBD_V5, File->getFileType()); 381 EXPECT_EQ(std::string("/usr/lib/libFoo.dylib"), File->getInstallName()); 382 EXPECT_TRUE(File->isApplicationExtensionSafe()); 383 EXPECT_TRUE(File->isTwoLevelNamespace()); 384 EXPECT_EQ(PackedVersion(1, 0, 0), File->getCurrentVersion()); 385 EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion()); 386 EXPECT_EQ(8U, File->getSwiftABIVersion()); 387 388 TargetList AllTargets = { 389 Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)), 390 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)), 391 Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)), 392 }; 393 EXPECT_EQ(mapToPlatformSet(AllTargets), File->getPlatforms()); 394 EXPECT_EQ(mapToArchitectureSet(AllTargets), File->getArchitectures()); 395 396 InterfaceFileRef ReexportA("/u/l/l/libArmOnly.dylib", 397 {Target(AK_arm64, PLATFORM_MACCATALYST)}); 398 InterfaceFileRef ReexportB("/u/l/l/libbar.dylib", 399 {Target(AK_x86_64, PLATFORM_MACCATALYST)}); 400 InterfaceFileRef ReexportC("/u/l/l/libfoo.dylib", 401 {Target(AK_x86_64, PLATFORM_MACCATALYST)}); 402 EXPECT_EQ(3U, File->reexportedLibraries().size()); 403 EXPECT_EQ(ReexportA, File->reexportedLibraries().at(0)); 404 EXPECT_EQ(ReexportB, File->reexportedLibraries().at(1)); 405 EXPECT_EQ(ReexportC, File->reexportedLibraries().at(2)); 406 } 407 408 TEST(TBDv5, ReadMultipleDocuments) { 409 static const char TBDv5File[] = R"({ 410 "tapi_tbd_version": 5, 411 "main_library": { 412 "target_info": [ 413 { 414 "target": "armv7-ios", 415 "min_deployment": "11.0" 416 } 417 ], 418 "install_names":[ 419 { "name":"/S/L/F/Foo.framework/Foo" } 420 ], 421 "reexported_libraries": [ 422 { "names": ["/u/l/l/libfoo.dylib"] } 423 ] 424 }, 425 "libraries": [ 426 { 427 "target_info": [ 428 { 429 "target": "armv7-ios", 430 "min_deployment": "11.0" 431 } 432 ], 433 "install_names":[ 434 { "name":"/u/l/l/libfoo.dylib" } 435 ], 436 "flags":[ 437 { "attributes": ["not_app_extension_safe"] } 438 ], 439 "exported_symbols": [ 440 { 441 "data": { 442 "thread_local": [ "_globalVar" ], 443 "objc_class": [ "ClassData" ], 444 "objc_eh_type": [ "ClassA", "ClassB" ] 445 }, 446 "text": { 447 "global": [ "_funcFoo" ] 448 } 449 } 450 ] 451 } 452 ]})"; 453 454 Expected<TBDFile> Result = 455 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd")); 456 EXPECT_TRUE(!!Result); 457 TBDFile File = std::move(Result.get()); 458 EXPECT_EQ(FileType::TBD_V5, File->getFileType()); 459 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName()); 460 EXPECT_TRUE(File->isTwoLevelNamespace()); 461 EXPECT_TRUE(File->isApplicationExtensionSafe()); 462 463 TargetList Targets(File->targets().begin(), File->targets().end()); 464 Target iOSTarget(AK_armv7, PLATFORM_IOS, VersionTuple(11, 0)); 465 EXPECT_EQ(TargetList{iOSTarget}, Targets); 466 std::vector<const Symbol *> Symbols(File->symbols().begin(), 467 File->symbols().end()); 468 EXPECT_EQ(0U, Symbols.size()); 469 470 InterfaceFileRef Reexport("/u/l/l/libfoo.dylib", {iOSTarget}); 471 EXPECT_EQ(1U, File->reexportedLibraries().size()); 472 EXPECT_EQ(Reexport, File->reexportedLibraries().at(0)); 473 474 // Check inlined library. 475 EXPECT_EQ(1U, File->documents().size()); 476 TBDReexportFile Document = File->documents().front(); 477 Targets = {Document->targets().begin(), Document->targets().end()}; 478 EXPECT_EQ(TargetList{iOSTarget}, Targets); 479 EXPECT_EQ(std::string("/u/l/l/libfoo.dylib"), Document->getInstallName()); 480 EXPECT_EQ(0U, Document->getSwiftABIVersion()); 481 EXPECT_TRUE(Document->isTwoLevelNamespace()); 482 EXPECT_FALSE(Document->isApplicationExtensionSafe()); 483 484 ExportedSymbolSeq Exports; 485 for (const auto *Sym : Document->symbols()) 486 Exports.emplace_back( 487 ExportedSymbol{Sym->getKind(), 488 std::string(Sym->getName()), 489 Sym->isWeakDefined() || Sym->isWeakReferenced(), 490 Sym->isThreadLocalValue(), 491 Sym->isData(), 492 {iOSTarget}}); 493 494 llvm::sort(Exports); 495 ExportedSymbolSeq ExpectedExports = { 496 {SymbolKind::GlobalSymbol, "_funcFoo", false, false, false, {iOSTarget}}, 497 {SymbolKind::GlobalSymbol, "_globalVar", false, true, true, {iOSTarget}}, 498 {SymbolKind::ObjectiveCClass, 499 "ClassData", 500 false, 501 false, 502 true, 503 {iOSTarget}}, 504 {SymbolKind::ObjectiveCClassEHType, 505 "ClassA", 506 false, 507 false, 508 true, 509 {iOSTarget}}, 510 {SymbolKind::ObjectiveCClassEHType, 511 "ClassB", 512 false, 513 false, 514 true, 515 {iOSTarget}}, 516 }; 517 518 EXPECT_EQ(ExpectedExports.size(), Exports.size()); 519 EXPECT_TRUE( 520 std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports))); 521 } 522 523 TEST(TBDv5, WriteFile) { 524 static const char TBDv5File[] = R"({ 525 "tapi_tbd_version": 5, 526 "main_library": { 527 "target_info": [ 528 { 529 "target": "x86_64-macos", 530 "min_deployment": "10.14" 531 }, 532 { 533 "target": "arm64-macos", 534 "min_deployment": "10.14" 535 }, 536 { 537 "target": "arm64-maccatalyst", 538 "min_deployment": "12.1" 539 } 540 ], 541 "install_names": [ 542 { 543 "name": "@rpath/S/L/F/Foo.framework/Foo" 544 } 545 ], 546 "current_versions": [ 547 { 548 "version": "1.2" 549 } 550 ], 551 "compatibility_versions": [ 552 { "version": "1.1" } 553 ], 554 "flags": [ 555 { 556 "attributes": [ 557 "flat_namespace" 558 ] 559 } 560 ], 561 "rpaths": [ 562 { 563 "targets": [ 564 "x86_64-macos" 565 ], 566 "paths": [ 567 "@executable_path/.../Frameworks" 568 ] 569 } 570 ], 571 "parent_umbrellas": [ 572 { 573 "umbrella": "System" 574 } 575 ], 576 "allowable_clients": [ 577 { 578 "clients": [ 579 "ClientA", 580 "ClientB" 581 ] 582 } 583 ], 584 "reexported_libraries": [ 585 { 586 "names": [ 587 "/u/l/l/libfoo.dylib", 588 "/u/l/l/libbar.dylib" 589 ] 590 } 591 ], 592 "exported_symbols": [ 593 { 594 "targets": [ 595 "x86_64-macos", 596 "arm64-macos" 597 ], 598 "data": { 599 "global": [ 600 "_global" 601 ], 602 "objc_class": [ 603 "ClassA" 604 ], 605 "weak": [], 606 "thread_local": [] 607 }, 608 "text": { 609 "global": [ 610 "_func" 611 ], 612 "weak": [], 613 "thread_local": [] 614 } 615 }, 616 { 617 "targets": [ 618 "x86_64-macos" 619 ], 620 "data": { 621 "global": [ 622 "_globalVar" 623 ], 624 "objc_class": [ 625 "ClassData" 626 ], 627 "objc_eh_type": [ 628 "ClassA", 629 "ClassB" 630 ], 631 "objc_ivar": [ 632 "ClassA.ivar1", 633 "ClassA.ivar2", 634 "ClassC.ivar1" 635 ] 636 }, 637 "text": { 638 "global": [ 639 "_funcFoo" 640 ] 641 } 642 } 643 ], 644 "reexported_symbols": [ 645 { 646 "data": { 647 "global": [ 648 "_globalRe" 649 ], 650 "objc_class": [ 651 "ClassRexport" 652 ] 653 }, 654 "text": { 655 "global": [ 656 "_funcA" 657 ] 658 } 659 } 660 ], 661 "undefined_symbols": [ 662 { 663 "targets": [ 664 "x86_64-macos" 665 ], 666 "data": { 667 "global": [ 668 "_globalBind" 669 ], 670 "weak": [ 671 "referenced_sym" 672 ] 673 } 674 } 675 ] 676 }})"; 677 678 InterfaceFile File; 679 File.setFileType(FileType::TBD_V5); 680 681 TargetList AllTargets = { 682 Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)), 683 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)), 684 Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)), 685 }; 686 File.addTargets(AllTargets); 687 File.setInstallName("@rpath/S/L/F/Foo.framework/Foo"); 688 File.setCurrentVersion(PackedVersion(1, 2, 0)); 689 File.setCompatibilityVersion(PackedVersion(1, 1, 0)); 690 File.addRPath(AllTargets[0], "@executable_path/.../Frameworks"); 691 692 for (const auto &Targ : AllTargets) { 693 File.addParentUmbrella(Targ, "System"); 694 File.addAllowableClient("ClientA", Targ); 695 File.addAllowableClient("ClientB", Targ); 696 File.addReexportedLibrary("/u/l/l/libfoo.dylib", Targ); 697 File.addReexportedLibrary("/u/l/l/libbar.dylib", Targ); 698 } 699 700 SymbolFlags Flags = SymbolFlags::None; 701 // Exports. 702 File.addSymbol(SymbolKind::GlobalSymbol, "_global", 703 {AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Data); 704 File.addSymbol(SymbolKind::GlobalSymbol, "_func", 705 {AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Text); 706 File.addSymbol(SymbolKind::ObjectiveCClass, "ClassA", 707 {AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Data); 708 File.addSymbol(SymbolKind::GlobalSymbol, "_funcFoo", {AllTargets[0]}, 709 Flags | SymbolFlags::Text); 710 File.addSymbol(SymbolKind::GlobalSymbol, "_globalVar", {AllTargets[0]}, 711 Flags | SymbolFlags::Data); 712 File.addSymbol(SymbolKind::ObjectiveCClass, "ClassData", {AllTargets[0]}, 713 Flags | SymbolFlags::Data); 714 File.addSymbol(SymbolKind::ObjectiveCClassEHType, "ClassA", {AllTargets[0]}, 715 Flags | SymbolFlags::Data); 716 File.addSymbol(SymbolKind::ObjectiveCClassEHType, "ClassB", {AllTargets[0]}, 717 Flags | SymbolFlags::Data); 718 File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "ClassA.ivar1", 719 {AllTargets[0]}, Flags | SymbolFlags::Data); 720 File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "ClassA.ivar2", 721 {AllTargets[0]}, Flags | SymbolFlags::Data); 722 File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "ClassC.ivar1", 723 {AllTargets[0]}, Flags | SymbolFlags::Data); 724 725 // Reexports. 726 Flags = SymbolFlags::Rexported; 727 File.addSymbol(SymbolKind::GlobalSymbol, "_globalRe", AllTargets, 728 Flags | SymbolFlags::Data); 729 File.addSymbol(SymbolKind::GlobalSymbol, "_funcA", AllTargets, 730 Flags | SymbolFlags::Text); 731 File.addSymbol(SymbolKind::ObjectiveCClass, "ClassRexport", AllTargets, 732 Flags | SymbolFlags::Data); 733 734 // Undefineds. 735 Flags = SymbolFlags::Undefined; 736 File.addSymbol(SymbolKind::GlobalSymbol, "_globalBind", {AllTargets[0]}, 737 Flags | SymbolFlags::Data); 738 File.addSymbol(SymbolKind::GlobalSymbol, "referenced_sym", {AllTargets[0]}, 739 Flags | SymbolFlags::Data | SymbolFlags::WeakReferenced); 740 741 File.setTwoLevelNamespace(false); 742 File.setApplicationExtensionSafe(true); 743 744 // Write out file then process it back into IF and compare equality 745 // against TBDv5File. 746 SmallString<4096> Buffer; 747 raw_svector_ostream OS(Buffer); 748 Error Result = TextAPIWriter::writeToStream(OS, File); 749 EXPECT_FALSE(Result); 750 751 Expected<TBDFile> Input = 752 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Input.tbd")); 753 EXPECT_TRUE(!!Input); 754 TBDFile InputFile = std::move(Input.get()); 755 756 Expected<TBDFile> Output = 757 TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd")); 758 EXPECT_TRUE(!!Output); 759 TBDFile OutputFile = std::move(Output.get()); 760 EXPECT_EQ(*InputFile, *OutputFile); 761 } 762 763 TEST(TBDv5, WriteMultipleDocuments) { 764 static const char TBDv5File[] = R"({ 765 "tapi_tbd_version": 5, 766 "main_library": { 767 "target_info": [ 768 { 769 "target": "armv7-ios", 770 "min_deployment": "11.0" 771 } 772 ], 773 "install_names":[ 774 { "name":"/S/L/F/Foo.framework/Foo" } 775 ], 776 "reexported_libraries": [ 777 { "names": ["/u/l/l/libfoo.dylib"] 778 } 779 ] 780 }, 781 "libraries": [ 782 { 783 "target_info": [ 784 { 785 "target": "armv7-ios", 786 "min_deployment": "11.0" 787 }, 788 { 789 "target": "armv7s-ios", 790 "min_deployment": "11.0" 791 } 792 ], 793 "install_names":[ 794 { "name":"/u/l/l/libfoo.dylib" } 795 ], 796 "current_versions": [ 797 { 798 "version": "2.1.1" 799 } 800 ], 801 "rpaths": [ 802 { 803 "targets": [ 804 "armv7-ios" 805 ], 806 "paths": [ 807 "@executable_path/.../Frameworks" 808 ] 809 }], 810 "reexported_libraries": [ { "names": ["@rpath/libfoo.dylib"] } ], 811 "flags":[ 812 { "attributes": ["not_app_extension_safe"] } 813 ], 814 "exported_symbols": [ 815 { 816 "text": { 817 "global": [ "_funcFoo" ] 818 } 819 } 820 ] 821 }, 822 { 823 "target_info": [ 824 { 825 "target": "armv7-ios", 826 "min_deployment": "11.0" 827 } 828 ], 829 "install_names":[ 830 { "name":"@rpath/libfoo.dylib" } 831 ], 832 "exported_symbols": [ 833 { 834 "data": { 835 "global": [ "_varFooBaz" ] 836 } 837 } 838 ] 839 } 840 ]})"; 841 842 InterfaceFile File; 843 File.setFileType(FileType::TBD_V5); 844 845 TargetList AllTargets = { 846 Target(AK_armv7, PLATFORM_IOS, VersionTuple(11, 0)), 847 Target(AK_armv7s, PLATFORM_IOS, VersionTuple(11, 0)), 848 }; 849 File.setInstallName("/S/L/F/Foo.framework/Foo"); 850 File.addTarget(AllTargets[0]); 851 File.setCurrentVersion(PackedVersion(1, 0, 0)); 852 File.setCompatibilityVersion(PackedVersion(1, 0, 0)); 853 File.addReexportedLibrary("/u/l/l/libfoo.dylib", AllTargets[0]); 854 File.setTwoLevelNamespace(); 855 File.setApplicationExtensionSafe(true); 856 857 InterfaceFile NestedFile; 858 NestedFile.setFileType(FileType::TBD_V5); 859 NestedFile.setInstallName("/u/l/l/libfoo.dylib"); 860 NestedFile.addTargets(AllTargets); 861 NestedFile.setCompatibilityVersion(PackedVersion(1, 0, 0)); 862 NestedFile.setTwoLevelNamespace(); 863 NestedFile.setApplicationExtensionSafe(false); 864 NestedFile.setCurrentVersion(PackedVersion(2, 1, 1)); 865 NestedFile.addRPath(AllTargets[0], "@executable_path/.../Frameworks"); 866 for (const auto &Targ : AllTargets) 867 NestedFile.addReexportedLibrary("@rpath/libfoo.dylib", Targ); 868 NestedFile.addSymbol(SymbolKind::GlobalSymbol, "_funcFoo", AllTargets, 869 SymbolFlags::Text); 870 File.addDocument(std::make_shared<InterfaceFile>(std::move(NestedFile))); 871 872 InterfaceFile NestedFileB; 873 NestedFileB.setFileType(FileType::TBD_V5); 874 NestedFileB.setInstallName("@rpath/libfoo.dylib"); 875 NestedFileB.addTarget(AllTargets[0]); 876 NestedFileB.setCompatibilityVersion(PackedVersion(1, 0, 0)); 877 NestedFileB.setCurrentVersion(PackedVersion(1, 0, 0)); 878 NestedFileB.setTwoLevelNamespace(); 879 NestedFileB.setApplicationExtensionSafe(true); 880 NestedFileB.addSymbol(SymbolKind::GlobalSymbol, "_varFooBaz", {AllTargets[0]}, 881 SymbolFlags::Data); 882 File.addDocument(std::make_shared<InterfaceFile>(std::move(NestedFileB))); 883 884 // Write out file then process it back into IF and compare equality 885 // against TBDv5File. 886 SmallString<4096> Buffer; 887 raw_svector_ostream OS(Buffer); 888 Error Result = TextAPIWriter::writeToStream(OS, File, /*Compact=*/true); 889 EXPECT_FALSE(Result); 890 891 Expected<TBDFile> Input = 892 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Input.tbd")); 893 EXPECT_TRUE(!!Input); 894 TBDFile InputFile = std::move(Input.get()); 895 896 Expected<TBDFile> Output = 897 TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd")); 898 EXPECT_TRUE(!!Output); 899 TBDFile OutputFile = std::move(Output.get()); 900 EXPECT_EQ(*InputFile, *OutputFile); 901 } 902 903 TEST(TBDv5, Target_Simulator) { 904 static const char TBDv5File[] = R"({ 905 "tapi_tbd_version": 5, 906 "main_library": { 907 "target_info": [ 908 { 909 "target": "arm64-ios-simulator", 910 "min_deployment": "11.0" 911 }, 912 { 913 "target": "x86_64-ios-simulator", 914 "min_deployment": "11.3" 915 } 916 ], 917 "install_names":[ 918 { "name":"/S/L/F/Foo.framework/Foo" } 919 ] 920 }})"; 921 922 Expected<TBDFile> Result = 923 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd")); 924 EXPECT_TRUE(!!Result); 925 TBDFile File = std::move(Result.get()); 926 EXPECT_EQ(FileType::TBD_V5, File->getFileType()); 927 TargetList ExpectedTargets = { 928 Target(AK_x86_64, PLATFORM_IOSSIMULATOR, VersionTuple(11, 3)), 929 Target(AK_arm64, PLATFORM_IOSSIMULATOR, VersionTuple(11, 0)), 930 }; 931 TargetList Targets{File->targets().begin(), File->targets().end()}; 932 llvm::sort(Targets); 933 EXPECT_EQ(Targets, ExpectedTargets); 934 935 SmallString<4096> Buffer; 936 raw_svector_ostream OS(Buffer); 937 Error WriteResult = TextAPIWriter::writeToStream(OS, *File); 938 EXPECT_TRUE(!WriteResult); 939 940 Expected<TBDFile> Output = 941 TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd")); 942 EXPECT_TRUE(!!Output); 943 TBDFile WriteResultFile = std::move(Output.get()); 944 EXPECT_EQ(*File, *WriteResultFile); 945 } 946 947 TEST(TBDv5, Target_UnsupportedMinOS) { 948 static const char TBDv5File[] = R"({ 949 "tapi_tbd_version": 5, 950 "main_library": { 951 "target_info": [ 952 { 953 "target": "arm64-macos", 954 "min_deployment": "10.14" 955 }, 956 { 957 "target": "x86_64-macos", 958 "min_deployment": "10.14" 959 } 960 ], 961 "install_names":[ 962 { "name":"/S/L/F/Foo.framework/Foo" } 963 ] 964 }})"; 965 966 Expected<TBDFile> Result = 967 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd")); 968 EXPECT_TRUE(!!Result); 969 TBDFile File = std::move(Result.get()); 970 EXPECT_EQ(FileType::TBD_V5, File->getFileType()); 971 TargetList ExpectedTargets = { 972 Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)), 973 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0)), 974 }; 975 TargetList Targets{File->targets().begin(), File->targets().end()}; 976 llvm::sort(Targets); 977 EXPECT_EQ(Targets, ExpectedTargets); 978 979 SmallString<4096> Buffer; 980 raw_svector_ostream OS(Buffer); 981 Error WriteResult = TextAPIWriter::writeToStream(OS, *File); 982 EXPECT_TRUE(!WriteResult); 983 984 Expected<TBDFile> Output = 985 TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd")); 986 EXPECT_TRUE(!!Output); 987 TBDFile WriteResultFile = std::move(Output.get()); 988 EXPECT_EQ(*File, *WriteResultFile); 989 } 990 991 TEST(TBDv5, MisspelledKey) { 992 static const char TBDv5File[] = R"({ 993 "tapi_tbd_version": 5, 994 "main_library": { 995 "target_info": [ 996 { 997 "target": "arm64-ios-simulator", 998 "min_deployment": "11.0" 999 } 1000 ], 1001 "intall_names":[ 1002 { "name":"/S/L/F/Foo.framework/Foo" } 1003 ] 1004 }})"; 1005 1006 Expected<TBDFile> Result = 1007 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd")); 1008 EXPECT_FALSE(!!Result); 1009 std::string ErrorMessage = toString(Result.takeError()); 1010 EXPECT_EQ("invalid install_names section\n", ErrorMessage); 1011 } 1012 1013 TEST(TBDv5, InvalidVersion) { 1014 static const char TBDv5File[] = R"({ 1015 "tapi_tbd_version": 11, 1016 "main_library": { 1017 "target_info": [ 1018 { 1019 "target": "arm64-ios-simulator", 1020 "min_deployment": "11.0" 1021 } 1022 ], 1023 "install_names":[ 1024 { "name":"/S/L/F/Foo.framework/Foo" } 1025 ] 1026 }})"; 1027 1028 Expected<TBDFile> Result = 1029 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd")); 1030 EXPECT_FALSE(!!Result); 1031 std::string ErrorMessage = toString(Result.takeError()); 1032 EXPECT_EQ("invalid tapi_tbd_version section\n", ErrorMessage); 1033 } 1034 1035 TEST(TBDv5, MissingRequiredKey) { 1036 static const char TBDv5File[] = R"({ 1037 "main_library": { 1038 "target_info": [ 1039 { 1040 "target": "arm64-ios-simulator", 1041 "min_deployment": "11.0" 1042 } 1043 ], 1044 "install_names":[ 1045 { "name":"/S/L/F/Foo.framework/Foo" } 1046 ] 1047 }})"; 1048 1049 Expected<TBDFile> Result = 1050 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd")); 1051 EXPECT_FALSE(!!Result); 1052 std::string ErrorMessage = toString(Result.takeError()); 1053 EXPECT_EQ("invalid tapi_tbd_version section\n", ErrorMessage); 1054 } 1055 1056 TEST(TBDv5, InvalidSymbols) { 1057 static const char TBDv5File[] = R"({ 1058 "tapi_tbd_version": 5, 1059 "main_library": { 1060 "target_info": [ 1061 { 1062 "target": "arm64-driverkit", 1063 "min_deployment": "11.0" 1064 } 1065 ], 1066 "install_names":[ 1067 { "name":"/S/L/F/Foo.framework/Foo" } 1068 ], 1069 "exported_symbols": [ 1070 { 1071 "daa": { 1072 "global": { 1073 "weak": [] 1074 } 1075 } 1076 } 1077 ] 1078 }})"; 1079 1080 Expected<TBDFile> Result = 1081 TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd")); 1082 EXPECT_FALSE(!!Result); 1083 std::string ErrorMessage = toString(Result.takeError()); 1084 EXPECT_EQ("invalid exported_symbols section\n", ErrorMessage); 1085 } 1086 1087 } // end namespace TBDv5 1088