492 lines · cpp
1//===-- TextStubV2Tests.cpp - TBD V2 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-exception6//7//===-----------------------------------------------------------------------===/8#include "TextStubHelpers.h"9#include "llvm/TextAPI/InterfaceFile.h"10#include "llvm/TextAPI/TextAPIReader.h"11#include "llvm/TextAPI/TextAPIWriter.h"12#include "gtest/gtest.h"13#include <string>14 15using namespace llvm;16using namespace llvm::MachO;17 18static ExportedSymbol TBDv2Symbols[] = {19 {EncodeKind::GlobalSymbol, "$ld$hide$os9.0$_sym1", false, false},20 {EncodeKind::GlobalSymbol, "_sym1", false, false},21 {EncodeKind::GlobalSymbol, "_sym2", false, false},22 {EncodeKind::GlobalSymbol, "_sym3", false, false},23 {EncodeKind::GlobalSymbol, "_sym4", false, false},24 {EncodeKind::GlobalSymbol, "_sym5", false, false},25 {EncodeKind::GlobalSymbol, "_tlv1", false, true},26 {EncodeKind::GlobalSymbol, "_tlv2", false, true},27 {EncodeKind::GlobalSymbol, "_tlv3", false, true},28 {EncodeKind::GlobalSymbol, "_weak1", true, false},29 {EncodeKind::GlobalSymbol, "_weak2", true, false},30 {EncodeKind::GlobalSymbol, "_weak3", true, false},31 {EncodeKind::ObjectiveCClass, "class1", false, false},32 {EncodeKind::ObjectiveCClass, "class2", false, false},33 {EncodeKind::ObjectiveCClass, "class3", false, false},34 {EncodeKind::ObjectiveCInstanceVariable, "class1._ivar1", false, false},35 {EncodeKind::ObjectiveCInstanceVariable, "class1._ivar2", false, false},36 {EncodeKind::ObjectiveCInstanceVariable, "class1._ivar3", false, false},37};38 39namespace TBDv2 {40 41TEST(TBDv2, ReadFile) {42 static const char TBDv2File1[] =43 "--- !tapi-tbd-v2\n"44 "archs: [ armv7, armv7s, armv7k, arm64 ]\n"45 "platform: ios\n"46 "flags: [ installapi ]\n"47 "install-name: Test.dylib\n"48 "current-version: 2.3.4\n"49 "compatibility-version: 1.0\n"50 "swift-version: 1.1\n"51 "parent-umbrella: Umbrella.dylib\n"52 "exports:\n"53 " - archs: [ armv7, armv7s, armv7k, arm64 ]\n"54 " allowable-clients: [ clientA ]\n"55 " re-exports: [ /usr/lib/libfoo.dylib ]\n"56 " symbols: [ _sym1, _sym2, _sym3, _sym4, $ld$hide$os9.0$_sym1 ]\n"57 " objc-classes: [ _class1, _class2 ]\n"58 " objc-ivars: [ _class1._ivar1, _class1._ivar2 ]\n"59 " weak-def-symbols: [ _weak1, _weak2 ]\n"60 " thread-local-symbols: [ _tlv1, _tlv2 ]\n"61 " - archs: [ armv7, armv7s, armv7k ]\n"62 " symbols: [ _sym5 ]\n"63 " objc-classes: [ _class3 ]\n"64 " objc-ivars: [ _class1._ivar3 ]\n"65 " weak-def-symbols: [ _weak3 ]\n"66 " thread-local-symbols: [ _tlv3 ]\n"67 "...\n";68 69 Expected<TBDFile> Result =70 TextAPIReader::get(MemoryBufferRef(TBDv2File1, "Test.tbd"));71 EXPECT_TRUE(!!Result);72 TBDFile File = std::move(Result.get());73 EXPECT_EQ(FileType::TBD_V2, File->getFileType());74 auto Archs = AK_armv7 | AK_armv7s | AK_armv7k | AK_arm64;75 auto Platform = PLATFORM_IOS;76 TargetList Targets;77 for (auto &&arch : Archs)78 Targets.emplace_back(Target(arch, Platform));79 EXPECT_EQ(Archs, File->getArchitectures());80 EXPECT_EQ(File->getPlatforms().size(), 1U);81 EXPECT_EQ(Platform, *File->getPlatforms().begin());82 EXPECT_EQ(std::string("Test.dylib"), File->getInstallName());83 EXPECT_EQ(PackedVersion(2, 3, 4), File->getCurrentVersion());84 EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());85 EXPECT_EQ(2U, File->getSwiftABIVersion());86 EXPECT_EQ(ObjCConstraintType::Retain_Release, File->getObjCConstraint());87 EXPECT_TRUE(File->isTwoLevelNamespace());88 EXPECT_TRUE(File->isApplicationExtensionSafe());89 InterfaceFileRef client("clientA", Targets);90 InterfaceFileRef reexport("/usr/lib/libfoo.dylib", Targets);91 EXPECT_EQ(1U, File->allowableClients().size());92 EXPECT_EQ(client, File->allowableClients().front());93 EXPECT_EQ(1U, File->reexportedLibraries().size());94 EXPECT_EQ(reexport, File->reexportedLibraries().front());95 96 ExportedSymbolSeq Exports;97 for (const auto *Sym : File->symbols()) {98 EXPECT_FALSE(Sym->isWeakReferenced());99 EXPECT_FALSE(Sym->isUndefined());100 Exports.emplace_back(101 ExportedSymbol{Sym->getKind(), std::string(Sym->getName()),102 Sym->isWeakDefined(), Sym->isThreadLocalValue()});103 }104 llvm::sort(Exports);105 106 EXPECT_EQ(std::size(TBDv2Symbols), Exports.size());107 EXPECT_TRUE(108 std::equal(Exports.begin(), Exports.end(), std::begin(TBDv2Symbols)));109}110 111TEST(TBDv2, ReadFile2) {112 static const char TBDv2File2[] =113 "--- !tapi-tbd-v2\n"114 "archs: [ armv7, armv7s, armv7k, arm64 ]\n"115 "platform: ios\n"116 "flags: [ flat_namespace, not_app_extension_safe ]\n"117 "install-name: Test.dylib\n"118 "swift-version: 1.1\n"119 "exports:\n"120 " - archs: [ armv7, armv7s, armv7k, arm64 ]\n"121 " symbols: [ _sym1, _sym2, _sym3, _sym4, $ld$hide$os9.0$_sym1 ]\n"122 " objc-classes: [ _class1, _class2 ]\n"123 " objc-ivars: [ _class1._ivar1, _class1._ivar2 ]\n"124 " weak-def-symbols: [ _weak1, _weak2 ]\n"125 " thread-local-symbols: [ _tlv1, _tlv2 ]\n"126 " - archs: [ armv7, armv7s, armv7k ]\n"127 " symbols: [ _sym5 ]\n"128 " objc-classes: [ _class3 ]\n"129 " objc-ivars: [ _class1._ivar3 ]\n"130 " weak-def-symbols: [ _weak3 ]\n"131 " thread-local-symbols: [ _tlv3 ]\n"132 "undefineds:\n"133 " - archs: [ armv7, armv7s, armv7k, arm64 ]\n"134 " symbols: [ _undefSym1, _undefSym2, _undefSym3 ]\n"135 " objc-classes: [ _undefClass1, _undefClass2 ]\n"136 " objc-ivars: [ _undefClass1._ivar1, _undefClass1._ivar2 ]\n"137 " weak-ref-symbols: [ _undefWeak1, _undefWeak2 ]\n"138 "...\n";139 140 Expected<TBDFile> Result =141 TextAPIReader::get(MemoryBufferRef(TBDv2File2, "Test.tbd"));142 EXPECT_TRUE(!!Result);143 TBDFile File = std::move(Result.get());144 EXPECT_EQ(FileType::TBD_V2, File->getFileType());145 auto Archs = AK_armv7 | AK_armv7s | AK_armv7k | AK_arm64;146 auto Platform = PLATFORM_IOS;147 TargetList Targets;148 for (auto &&arch : Archs)149 Targets.emplace_back(Target(arch, Platform));150 EXPECT_EQ(Archs, File->getArchitectures());151 EXPECT_EQ(File->getPlatforms().size(), 1U);152 EXPECT_EQ(Platform, *File->getPlatforms().begin());153 EXPECT_EQ(std::string("Test.dylib"), File->getInstallName());154 EXPECT_EQ(PackedVersion(1, 0, 0), File->getCurrentVersion());155 EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());156 EXPECT_EQ(2U, File->getSwiftABIVersion());157 EXPECT_EQ(ObjCConstraintType::Retain_Release, File->getObjCConstraint());158 EXPECT_FALSE(File->isTwoLevelNamespace());159 EXPECT_FALSE(File->isApplicationExtensionSafe());160 EXPECT_EQ(0U, File->allowableClients().size());161 EXPECT_EQ(0U, File->reexportedLibraries().size());162}163 164TEST(TBDv2, WriteFile) {165 static const char TBDv2File3[] =166 "--- !tapi-tbd-v2\n"167 "archs: [ i386, x86_64 ]\n"168 "platform: macosx\n"169 "install-name: '/usr/lib/libfoo.dylib'\n"170 "current-version: 1.2.3\n"171 "compatibility-version: 0\n"172 "swift-version: 5\n"173 "exports:\n"174 " - archs: [ i386 ]\n"175 " symbols: [ _sym1 ]\n"176 " weak-def-symbols: [ _sym2 ]\n"177 " thread-local-symbols: [ _sym3 ]\n"178 " - archs: [ x86_64 ]\n"179 " allowable-clients: [ clientA ]\n"180 " re-exports: [ '/usr/lib/libfoo.dylib' ]\n"181 " symbols: [ '_OBJC_EHTYPE_$_Class1' ]\n"182 " objc-classes: [ _Class1 ]\n"183 " objc-ivars: [ _Class1._ivar1 ]\n"184 "...\n";185 186 InterfaceFile File;187 TargetList Targets;188 for (auto &&arch : AK_i386 | AK_x86_64)189 Targets.emplace_back(Target(arch, PLATFORM_MACOS));190 File.setPath("libfoo.dylib");191 File.setInstallName("/usr/lib/libfoo.dylib");192 File.setFileType(FileType::TBD_V2);193 File.addTargets(Targets);194 File.setCurrentVersion(PackedVersion(1, 2, 3));195 File.setTwoLevelNamespace();196 File.setApplicationExtensionSafe();197 File.setSwiftABIVersion(5);198 File.setObjCConstraint(ObjCConstraintType::Retain_Release);199 File.addAllowableClient("clientA", Targets[1]);200 File.addReexportedLibrary("/usr/lib/libfoo.dylib", Targets[1]);201 File.addSymbol(EncodeKind::GlobalSymbol, "_sym1", {Targets[0]});202 File.addSymbol(EncodeKind::GlobalSymbol, "_sym2", {Targets[0]},203 SymbolFlags::WeakDefined);204 File.addSymbol(EncodeKind::GlobalSymbol, "_sym3", {Targets[0]},205 SymbolFlags::ThreadLocalValue);206 File.addSymbol(EncodeKind::ObjectiveCClass, "Class1", {Targets[1]});207 File.addSymbol(EncodeKind::ObjectiveCClassEHType, "Class1", {Targets[1]});208 File.addSymbol(EncodeKind::ObjectiveCInstanceVariable, "Class1._ivar1",209 {Targets[1]});210 211 SmallString<4096> Buffer;212 raw_svector_ostream OS(Buffer);213 Error Result = TextAPIWriter::writeToStream(OS, File);214 EXPECT_FALSE(Result);215 EXPECT_STREQ(TBDv2File3, Buffer.c_str());216}217 218TEST(TBDv2, Platform_macOS) {219 static const char TBDv2PlatformMacOS[] = "--- !tapi-tbd-v2\n"220 "archs: [ x86_64 ]\n"221 "platform: macosx\n"222 "install-name: Test.dylib\n"223 "...\n";224 225 Expected<TBDFile> Result =226 TextAPIReader::get(MemoryBufferRef(TBDv2PlatformMacOS, "Test.tbd"));227 EXPECT_TRUE(!!Result);228 TBDFile File = std::move(Result.get());229 auto Platform = PLATFORM_MACOS;230 EXPECT_EQ(FileType::TBD_V2, File->getFileType());231 EXPECT_EQ(File->getPlatforms().size(), 1U);232 EXPECT_EQ(Platform, *File->getPlatforms().begin());233}234 235TEST(TBDv2, Platform_iOS) {236 static const char TBDv2PlatformiOS[] = "--- !tapi-tbd-v2\n"237 "archs: [ arm64 ]\n"238 "platform: ios\n"239 "install-name: Test.dylib\n"240 "...\n";241 242 Expected<TBDFile> Result =243 TextAPIReader::get(MemoryBufferRef(TBDv2PlatformiOS, "Test.tbd"));244 EXPECT_TRUE(!!Result);245 auto Platform = PLATFORM_IOS;246 TBDFile File = std::move(Result.get());247 EXPECT_EQ(FileType::TBD_V2, File->getFileType());248 EXPECT_EQ(File->getPlatforms().size(), 1U);249 EXPECT_EQ(Platform, *File->getPlatforms().begin());250}251 252TEST(TBDv2, Platform_watchOS) {253 static const char TBDv2PlatformWatchOS[] = "--- !tapi-tbd-v2\n"254 "archs: [ armv7k ]\n"255 "platform: watchos\n"256 "install-name: Test.dylib\n"257 "...\n";258 259 Expected<TBDFile> Result =260 TextAPIReader::get(MemoryBufferRef(TBDv2PlatformWatchOS, "Test.tbd"));261 EXPECT_TRUE(!!Result);262 auto Platform = PLATFORM_WATCHOS;263 TBDFile File = std::move(Result.get());264 EXPECT_EQ(FileType::TBD_V2, File->getFileType());265 EXPECT_EQ(File->getPlatforms().size(), 1U);266 EXPECT_EQ(Platform, *File->getPlatforms().begin());267}268 269TEST(TBDv2, Platform_tvOS) {270 static const char TBDv2PlatformtvOS[] = "--- !tapi-tbd-v2\n"271 "archs: [ arm64 ]\n"272 "platform: tvos\n"273 "install-name: Test.dylib\n"274 "...\n";275 276 Expected<TBDFile> Result =277 TextAPIReader::get(MemoryBufferRef(TBDv2PlatformtvOS, "Test.tbd"));278 EXPECT_TRUE(!!Result);279 auto Platform = PLATFORM_TVOS;280 TBDFile File = std::move(Result.get());281 EXPECT_EQ(FileType::TBD_V2, File->getFileType());282 EXPECT_EQ(File->getPlatforms().size(), 1U);283 EXPECT_EQ(Platform, *File->getPlatforms().begin());284}285 286TEST(TBDv2, Platform_bridgeOS) {287 static const char TBDv2BridgeOS[] = "--- !tapi-tbd-v2\n"288 "archs: [ armv7k ]\n"289 "platform: bridgeos\n"290 "install-name: Test.dylib\n"291 "...\n";292 293 Expected<TBDFile> Result =294 TextAPIReader::get(MemoryBufferRef(TBDv2BridgeOS, "Test.tbd"));295 EXPECT_TRUE(!!Result);296 auto Platform = PLATFORM_BRIDGEOS;297 TBDFile File = std::move(Result.get());298 EXPECT_EQ(FileType::TBD_V2, File->getFileType());299 EXPECT_EQ(File->getPlatforms().size(), 1U);300 EXPECT_EQ(Platform, *File->getPlatforms().begin());301}302 303TEST(TBDv2, Swift_1_0) {304 static const char TBDv2Swift1[] = "--- !tapi-tbd-v2\n"305 "archs: [ arm64 ]\n"306 "platform: ios\n"307 "install-name: Test.dylib\n"308 "swift-version: 1.0\n"309 "...\n";310 311 Expected<TBDFile> Result =312 TextAPIReader::get(MemoryBufferRef(TBDv2Swift1, "Test.tbd"));313 EXPECT_TRUE(!!Result);314 TBDFile File = std::move(Result.get());315 EXPECT_EQ(FileType::TBD_V2, File->getFileType());316 EXPECT_EQ(1U, File->getSwiftABIVersion());317}318 319TEST(TBDv2, Swift_1_1) {320 static const char TBDv2Swift1dot[] = "--- !tapi-tbd-v2\n"321 "archs: [ arm64 ]\n"322 "platform: ios\n"323 "install-name: Test.dylib\n"324 "swift-version: 1.1\n"325 "...\n";326 327 Expected<TBDFile> Result =328 TextAPIReader::get(MemoryBufferRef(TBDv2Swift1dot, "Test.tbd"));329 EXPECT_TRUE(!!Result);330 TBDFile File = std::move(Result.get());331 EXPECT_EQ(FileType::TBD_V2, File->getFileType());332 EXPECT_EQ(2U, File->getSwiftABIVersion());333}334 335TEST(TBDv2, Swift_2_0) {336 static const char tbd_v2_swift_2_0[] = "--- !tapi-tbd-v2\n"337 "archs: [ arm64 ]\n"338 "platform: ios\n"339 "install-name: Test.dylib\n"340 "swift-version: 2.0\n"341 "...\n";342 343 Expected<TBDFile> Result =344 TextAPIReader::get(MemoryBufferRef(tbd_v2_swift_2_0, "Test.tbd"));345 EXPECT_TRUE(!!Result);346 TBDFile File = std::move(Result.get());347 EXPECT_EQ(FileType::TBD_V2, File->getFileType());348 EXPECT_EQ(3U, File->getSwiftABIVersion());349}350 351TEST(TBDv2, Swift_3_0) {352 static const char TBDv2Swift3[] = "--- !tapi-tbd-v2\n"353 "archs: [ arm64 ]\n"354 "platform: ios\n"355 "install-name: Test.dylib\n"356 "swift-version: 3.0\n"357 "...\n";358 359 Expected<TBDFile> Result =360 TextAPIReader::get(MemoryBufferRef(TBDv2Swift3, "Test.tbd"));361 EXPECT_TRUE(!!Result);362 TBDFile File = std::move(Result.get());363 EXPECT_EQ(FileType::TBD_V2, File->getFileType());364 EXPECT_EQ(4U, File->getSwiftABIVersion());365}366 367TEST(TBDv2, Swift_4_0) {368 static const char TBDv2Swift4[] = "--- !tapi-tbd-v2\n"369 "archs: [ arm64 ]\n"370 "platform: ios\n"371 "install-name: Test.dylib\n"372 "swift-version: 4.0\n"373 "...\n";374 375 Expected<TBDFile> Result =376 TextAPIReader::get(MemoryBufferRef(TBDv2Swift4, "Test.tbd"));377 EXPECT_FALSE(!!Result);378 std::string ErrorMessage = toString(Result.takeError());379 EXPECT_EQ("malformed file\nTest.tbd:5:16: error: invalid Swift ABI "380 "version.\nswift-version: 4.0\n ^~~\n",381 ErrorMessage);382}383 384TEST(TBDv2, Swift_5) {385 static const char TBDv2Swift5[] = "--- !tapi-tbd-v2\n"386 "archs: [ arm64 ]\n"387 "platform: ios\n"388 "install-name: Test.dylib\n"389 "swift-version: 5\n"390 "...\n";391 392 Expected<TBDFile> Result =393 TextAPIReader::get(MemoryBufferRef(TBDv2Swift5, "Test.tbd"));394 EXPECT_TRUE(!!Result);395 TBDFile File = std::move(Result.get());396 EXPECT_EQ(FileType::TBD_V2, File->getFileType());397 EXPECT_EQ(5U, File->getSwiftABIVersion());398}399 400TEST(TBDv2, Swift_99) {401 static const char TBDv2Swift99[] = "--- !tapi-tbd-v2\n"402 "archs: [ arm64 ]\n"403 "platform: ios\n"404 "install-name: Test.dylib\n"405 "swift-version: 99\n"406 "...\n";407 408 Expected<TBDFile> Result =409 TextAPIReader::get(MemoryBufferRef(TBDv2Swift99, "Test.tbd"));410 EXPECT_TRUE(!!Result);411 TBDFile File = std::move(Result.get());412 EXPECT_EQ(FileType::TBD_V2, File->getFileType());413 EXPECT_EQ(99U, File->getSwiftABIVersion());414}415 416TEST(TBDv2, UnknownArchitecture) {417 static const char TBDv2FileUnknownArch[] = "--- !tapi-tbd-v2\n"418 "archs: [ foo ]\n"419 "platform: macosx\n"420 "install-name: Test.dylib\n"421 "...\n";422 Expected<TBDFile> Result =423 TextAPIReader::get(MemoryBufferRef(TBDv2FileUnknownArch, "Test.tbd"));424 EXPECT_TRUE(!!Result);425}426 427TEST(TBDv2, UnknownPlatform) {428 static const char TBDv2FileUnknownPlatform[] = "--- !tapi-tbd-v2\n"429 "archs: [ i386 ]\n"430 "platform: newOS\n"431 "...\n";432 433 Expected<TBDFile> Result =434 TextAPIReader::get(MemoryBufferRef(TBDv2FileUnknownPlatform, "Test.tbd"));435 EXPECT_FALSE(!!Result);436 std::string ErrorMessage = toString(Result.takeError());437 EXPECT_EQ("malformed file\nTest.tbd:3:11: error: unknown platform\nplatform: "438 "newOS\n ^~~~~\n",439 ErrorMessage);440}441 442TEST(TBDv2, InvalidPlatform) {443 static const char TBDv2FileInvalidPlatform[] = "--- !tapi-tbd-v2\n"444 "archs: [ i386 ]\n"445 "platform: iosmac\n"446 "install-name: Test.dylib\n"447 "...\n";448 449 Expected<TBDFile> Result =450 TextAPIReader::get(MemoryBufferRef(TBDv2FileInvalidPlatform, "Test.tbd"));451 EXPECT_FALSE(!!Result);452 std::string ErrorMessage = toString(Result.takeError());453 EXPECT_EQ("malformed file\nTest.tbd:3:11: error: invalid platform\nplatform: "454 "iosmac\n ^~~~~~\n",455 ErrorMessage);456}457 458TEST(TBDv2, MalformedFile1) {459 static const char TBDv2FileMalformed1[] = "--- !tapi-tbd-v2\n"460 "archs: [ arm64 ]\n"461 "foobar: \"Unsupported key\"\n"462 "...\n";463 464 Expected<TBDFile> Result =465 TextAPIReader::get(MemoryBufferRef(TBDv2FileMalformed1, "Test.tbd"));466 EXPECT_FALSE(!!Result);467 std::string ErrorMessage = toString(Result.takeError());468 ASSERT_EQ("malformed file\nTest.tbd:2:1: error: missing required key "469 "'platform'\narchs: [ arm64 ]\n^\n",470 ErrorMessage);471}472 473TEST(TBDv2, MalformedFile2) {474 static const char TBDv2FileMalformed2[] = "--- !tapi-tbd-v2\n"475 "archs: [ arm64 ]\n"476 "platform: ios\n"477 "install-name: Test.dylib\n"478 "foobar: \"Unsupported key\"\n"479 "...\n";480 481 Expected<TBDFile> Result =482 TextAPIReader::get(MemoryBufferRef(TBDv2FileMalformed2, "Test.tbd"));483 EXPECT_FALSE(!!Result);484 std::string ErrorMessage = toString(Result.takeError());485 ASSERT_EQ(486 "malformed file\nTest.tbd:5:1: error: unknown key 'foobar'\nfoobar: "487 "\"Unsupported key\"\n^~~~~~\n",488 ErrorMessage);489}490 491} // namespace TBDv2492