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