1 //===-- TextStubV3Tests.cpp - TBD V3 File Test ----------------------------===//
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
7 //===-----------------------------------------------------------------------===/
9 #include "llvm/TextAPI/MachO/InterfaceFile.h"
10 #include "llvm/TextAPI/MachO/TextAPIReader.h"
11 #include "llvm/TextAPI/MachO/TextAPIWriter.h"
12 #include "gtest/gtest.h"
17 using namespace llvm::MachO
;
19 struct ExportedSymbol
{
23 bool ThreadLocalValue
;
25 using ExportedSymbolSeq
= std::vector
<ExportedSymbol
>;
26 using UUIDs
= std::vector
<std::pair
<Target
, std::string
>>;
28 inline bool operator<(const ExportedSymbol
&lhs
, const ExportedSymbol
&rhs
) {
29 return std::tie(lhs
.Kind
, lhs
.Name
) < std::tie(rhs
.Kind
, rhs
.Name
);
32 inline bool operator==(const ExportedSymbol
&lhs
, const ExportedSymbol
&rhs
) {
33 return std::tie(lhs
.Kind
, lhs
.Name
, lhs
.WeakDefined
, lhs
.ThreadLocalValue
) ==
34 std::tie(rhs
.Kind
, rhs
.Name
, rhs
.WeakDefined
, rhs
.ThreadLocalValue
);
37 static ExportedSymbol TBDv3Symbols
[] = {
38 {SymbolKind::GlobalSymbol
, "$ld$hide$os9.0$_sym1", false, false},
39 {SymbolKind::GlobalSymbol
, "_sym1", false, false},
40 {SymbolKind::GlobalSymbol
, "_sym2", false, false},
41 {SymbolKind::GlobalSymbol
, "_sym3", false, false},
42 {SymbolKind::GlobalSymbol
, "_sym4", false, false},
43 {SymbolKind::GlobalSymbol
, "_sym5", false, false},
44 {SymbolKind::GlobalSymbol
, "_tlv1", false, true},
45 {SymbolKind::GlobalSymbol
, "_tlv3", false, true},
46 {SymbolKind::GlobalSymbol
, "_weak1", true, false},
47 {SymbolKind::GlobalSymbol
, "_weak2", true, false},
48 {SymbolKind::GlobalSymbol
, "_weak3", true, false},
49 {SymbolKind::ObjectiveCClass
, "class1", false, false},
50 {SymbolKind::ObjectiveCClass
, "class2", false, false},
51 {SymbolKind::ObjectiveCClass
, "class3", false, false},
52 {SymbolKind::ObjectiveCClassEHType
, "class1", false, false},
53 {SymbolKind::ObjectiveCInstanceVariable
, "class1._ivar1", false, false},
54 {SymbolKind::ObjectiveCInstanceVariable
, "class1._ivar2", false, false},
55 {SymbolKind::ObjectiveCInstanceVariable
, "class1._ivar3", false, false},
60 TEST(TBDv3
, ReadFile
) {
61 static const char tbd_v3_file1
[] =
63 "archs: [ armv7, arm64 ]\n"
64 "uuids: [ 'armv7: 00000000-0000-0000-0000-000000000000',\n"
65 " 'arm64: 11111111-1111-1111-1111-111111111111']\n"
67 "flags: [ installapi ]\n"
68 "install-name: Test.dylib\n"
69 "current-version: 2.3.4\n"
70 "compatibility-version: 1.0\n"
71 "swift-abi-version: 1.1\n"
72 "parent-umbrella: Umbrella.dylib\n"
74 " - archs: [ armv7, arm64 ]\n"
75 " allowable-clients: [ clientA ]\n"
76 " re-exports: [ /usr/lib/libfoo.dylib ]\n"
77 " symbols: [ _sym1, _sym2, _sym3, _sym4, $ld$hide$os9.0$_sym1 ]\n"
78 " objc-classes: [ class1, class2 ]\n"
79 " objc-eh-types: [ class1 ]\n"
80 " objc-ivars: [ class1._ivar1, class1._ivar2 ]\n"
81 " weak-def-symbols: [ _weak1, _weak2 ]\n"
82 " thread-local-symbols: [ _tlv1, _tlv3 ]\n"
83 " - archs: [ armv7 ]\n"
84 " symbols: [ _sym5 ]\n"
85 " objc-classes: [ class3 ]\n"
86 " objc-ivars: [ class1._ivar3 ]\n"
87 " weak-def-symbols: [ _weak3 ]\n"
88 " thread-local-symbols: [ _tlv3 ]\n"
91 auto Result
= TextAPIReader::get(MemoryBufferRef(tbd_v3_file1
, "Test.tbd"));
92 EXPECT_TRUE(!!Result
);
93 auto File
= std::move(Result
.get());
94 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
95 auto Archs
= AK_armv7
| AK_arm64
;
96 auto Platform
= PlatformKind::iOS
;
98 for (auto &&arch
: Archs
)
99 Targets
.emplace_back(Target(arch
, Platform
));
100 EXPECT_EQ(Archs
, File
->getArchitectures());
101 UUIDs Uuids
= {{Target(AK_armv7
, PlatformKind::unknown
),
102 "00000000-0000-0000-0000-000000000000"},
103 {Target(AK_arm64
, PlatformKind::unknown
),
104 "11111111-1111-1111-1111-111111111111"}};
105 EXPECT_EQ(Uuids
, File
->uuids());
106 EXPECT_EQ(File
->getPlatforms().size(), 1U);
107 EXPECT_EQ(Platform
, *File
->getPlatforms().begin());
108 EXPECT_EQ(std::string("Test.dylib"), File
->getInstallName());
109 EXPECT_EQ(PackedVersion(2, 3, 4), File
->getCurrentVersion());
110 EXPECT_EQ(PackedVersion(1, 0, 0), File
->getCompatibilityVersion());
111 EXPECT_EQ(2U, File
->getSwiftABIVersion());
112 EXPECT_EQ(ObjCConstraintType::Retain_Release
, File
->getObjCConstraint());
113 EXPECT_TRUE(File
->isTwoLevelNamespace());
114 EXPECT_TRUE(File
->isApplicationExtensionSafe());
115 EXPECT_TRUE(File
->isInstallAPI());
116 InterfaceFileRef
client("clientA", Targets
);
117 InterfaceFileRef
reexport("/usr/lib/libfoo.dylib", Targets
);
118 EXPECT_EQ(1U, File
->allowableClients().size());
119 EXPECT_EQ(client
, File
->allowableClients().front());
120 EXPECT_EQ(1U, File
->reexportedLibraries().size());
121 EXPECT_EQ(reexport
, File
->reexportedLibraries().front());
123 ExportedSymbolSeq Exports
;
124 for (const auto *Sym
: File
->symbols()) {
125 EXPECT_FALSE(Sym
->isWeakReferenced());
126 EXPECT_FALSE(Sym
->isUndefined());
127 Exports
.emplace_back(ExportedSymbol
{Sym
->getKind(), Sym
->getName(),
128 Sym
->isWeakDefined(),
129 Sym
->isThreadLocalValue()});
131 llvm::sort(Exports
.begin(), Exports
.end());
133 EXPECT_EQ(sizeof(TBDv3Symbols
) / sizeof(ExportedSymbol
), Exports
.size());
135 std::equal(Exports
.begin(), Exports
.end(), std::begin(TBDv3Symbols
)));
138 TEST(TBDv3
, WriteFile
) {
139 static const char tbd_v3_file3
[] =
141 "archs: [ i386, x86_64 ]\n"
143 "install-name: '/usr/lib/libfoo.dylib'\n"
144 "current-version: 1.2.3\n"
145 "compatibility-version: 0\n"
146 "swift-abi-version: 5\n"
148 " - archs: [ i386 ]\n"
149 " symbols: [ _sym1 ]\n"
150 " weak-def-symbols: [ _sym2 ]\n"
151 " thread-local-symbols: [ _sym3 ]\n"
152 " - archs: [ x86_64 ]\n"
153 " allowable-clients: [ clientA ]\n"
154 " re-exports: [ '/usr/lib/libfoo.dylib' ]\n"
155 " objc-classes: [ Class1 ]\n"
156 " objc-eh-types: [ Class1 ]\n"
157 " objc-ivars: [ Class1._ivar1 ]\n"
162 for (auto &&arch
: AK_i386
| AK_x86_64
)
163 Targets
.emplace_back(Target(arch
, PlatformKind::macOS
));
164 File
.setPath("libfoo.dylib");
165 File
.setInstallName("/usr/lib/libfoo.dylib");
166 File
.setFileType(FileType::TBD_V3
);
167 File
.addTargets(Targets
);
168 File
.setCurrentVersion(PackedVersion(1, 2, 3));
169 File
.setTwoLevelNamespace();
170 File
.setApplicationExtensionSafe();
171 File
.setSwiftABIVersion(5);
172 File
.setObjCConstraint(ObjCConstraintType::Retain_Release
);
173 File
.addAllowableClient("clientA", Targets
[1]);
174 File
.addReexportedLibrary("/usr/lib/libfoo.dylib", Targets
[1]);
175 File
.addSymbol(SymbolKind::GlobalSymbol
, "_sym1", {Targets
[0]});
176 File
.addSymbol(SymbolKind::GlobalSymbol
, "_sym2", {Targets
[0]},
177 SymbolFlags::WeakDefined
);
178 File
.addSymbol(SymbolKind::GlobalSymbol
, "_sym3", {Targets
[0]},
179 SymbolFlags::ThreadLocalValue
);
180 File
.addSymbol(SymbolKind::ObjectiveCClass
, "Class1", {Targets
[1]});
181 File
.addSymbol(SymbolKind::ObjectiveCClassEHType
, "Class1", {Targets
[1]});
182 File
.addSymbol(SymbolKind::ObjectiveCInstanceVariable
, "Class1._ivar1",
185 SmallString
<4096> Buffer
;
186 raw_svector_ostream
OS(Buffer
);
187 auto Result
= TextAPIWriter::writeToStream(OS
, File
);
188 EXPECT_FALSE(Result
);
189 EXPECT_STREQ(tbd_v3_file3
, Buffer
.c_str());
192 TEST(TBDv3
, Platform_macOS
) {
193 static const char tbd_v1_platform_macos
[] = "--- !tapi-tbd-v3\n"
194 "archs: [ x86_64 ]\n"
196 "install-name: Test.dylib\n"
200 TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_macos
, "Test.tbd"));
201 EXPECT_TRUE(!!Result
);
202 auto Platform
= PlatformKind::macOS
;
203 auto File
= std::move(Result
.get());
204 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
205 EXPECT_EQ(File
->getPlatforms().size(), 1U);
206 EXPECT_EQ(Platform
, *File
->getPlatforms().begin());
209 TEST(TBDv3
, Platform_iOS
) {
210 static const char tbd_v1_platform_ios
[] = "--- !tapi-tbd-v3\n"
213 "install-name: Test.dylib\n"
217 TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_ios
, "Test.tbd"));
218 EXPECT_TRUE(!!Result
);
219 auto Platform
= PlatformKind::iOS
;
220 auto File
= std::move(Result
.get());
221 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
222 EXPECT_EQ(File
->getPlatforms().size(), 1U);
223 EXPECT_EQ(Platform
, *File
->getPlatforms().begin());
226 TEST(TBDv3
, Platform_watchOS
) {
227 static const char tbd_v1_platform_watchos
[] = "--- !tapi-tbd-v3\n"
228 "archs: [ armv7k ]\n"
229 "platform: watchos\n"
230 "install-name: Test.dylib\n"
234 TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_watchos
, "Test.tbd"));
235 EXPECT_TRUE(!!Result
);
236 auto Platform
= PlatformKind::watchOS
;
237 auto File
= std::move(Result
.get());
238 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
239 EXPECT_EQ(File
->getPlatforms().size(), 1U);
240 EXPECT_EQ(Platform
, *File
->getPlatforms().begin());
243 TEST(TBDv3
, Platform_tvOS
) {
244 static const char tbd_v1_platform_tvos
[] = "--- !tapi-tbd-v3\n"
247 "install-name: Test.dylib\n"
251 TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_tvos
, "Test.tbd"));
252 EXPECT_TRUE(!!Result
);
253 auto File
= std::move(Result
.get());
254 auto Platform
= PlatformKind::tvOS
;
255 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
256 EXPECT_EQ(File
->getPlatforms().size(), 1U);
257 EXPECT_EQ(Platform
, *File
->getPlatforms().begin());
260 TEST(TBDv3
, Platform_bridgeOS
) {
261 static const char tbd_v1_platform_bridgeos
[] = "--- !tapi-tbd-v3\n"
262 "archs: [ armv7k ]\n"
263 "platform: bridgeos\n"
264 "install-name: Test.dylib\n"
268 TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_bridgeos
, "Test.tbd"));
269 EXPECT_TRUE(!!Result
);
270 auto Platform
= PlatformKind::bridgeOS
;
271 auto File
= std::move(Result
.get());
272 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
273 EXPECT_EQ(File
->getPlatforms().size(), 1U);
274 EXPECT_EQ(Platform
, *File
->getPlatforms().begin());
277 TEST(TBDv3
, Platform_macCatalyst
) {
278 static const char tbd_v1_platform_iosmac
[] = "--- !tapi-tbd-v3\n"
279 "archs: [ armv7k ]\n"
281 "install-name: Test.dylib\n"
285 TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_iosmac
, "Test.tbd"));
286 EXPECT_TRUE(!!Result
);
287 auto Platform
= PlatformKind::macCatalyst
;
288 auto File
= std::move(Result
.get());
289 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
290 EXPECT_EQ(Platform
, *File
->getPlatforms().begin());
293 TEST(TBDv3
, Platform_zippered
) {
294 static const char tbd_v1_platform_zip
[] = "--- !tapi-tbd-v3\n"
295 "archs: [ armv7k ]\n"
296 "platform: zippered\n"
297 "install-name: Test.dylib\n"
301 TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_zip
, "Test.tbd"));
302 EXPECT_TRUE(!!Result
);
303 auto File
= std::move(Result
.get());
304 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
306 PlatformSet Platforms
;
307 Platforms
.insert(PlatformKind::macOS
);
308 Platforms
.insert(PlatformKind::macCatalyst
);
309 EXPECT_EQ(Platforms
.size(), File
->getPlatforms().size());
310 for (auto Platform
: File
->getPlatforms())
311 EXPECT_EQ(Platforms
.count(Platform
), 1U);
314 TEST(TBDv3
, Swift_1_0
) {
315 static const char tbd_v1_swift_1_0
[] = "--- !tapi-tbd-v3\n"
318 "install-name: Test.dylib\n"
319 "swift-abi-version: 1.0\n"
323 TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_1_0
, "Test.tbd"));
324 EXPECT_TRUE(!!Result
);
325 auto File
= std::move(Result
.get());
326 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
327 EXPECT_EQ(1U, File
->getSwiftABIVersion());
330 TEST(TBDv3
, Swift_1_1
) {
331 static const char tbd_v1_swift_1_1
[] = "--- !tapi-tbd-v3\n"
334 "install-name: Test.dylib\n"
335 "swift-abi-version: 1.1\n"
339 TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_1_1
, "Test.tbd"));
340 EXPECT_TRUE(!!Result
);
341 auto File
= std::move(Result
.get());
342 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
343 EXPECT_EQ(2U, File
->getSwiftABIVersion());
346 TEST(TBDv3
, Swift_2_0
) {
347 static const char tbd_v1_swift_2_0
[] = "--- !tapi-tbd-v3\n"
350 "install-name: Test.dylib\n"
351 "swift-abi-version: 2.0\n"
355 TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_2_0
, "Test.tbd"));
356 EXPECT_TRUE(!!Result
);
357 auto File
= std::move(Result
.get());
358 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
359 EXPECT_EQ(3U, File
->getSwiftABIVersion());
362 TEST(TBDv3
, Swift_3_0
) {
363 static const char tbd_v1_swift_3_0
[] = "--- !tapi-tbd-v3\n"
366 "install-name: Test.dylib\n"
367 "swift-abi-version: 3.0\n"
371 TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_3_0
, "Test.tbd"));
372 EXPECT_TRUE(!!Result
);
373 auto File
= std::move(Result
.get());
374 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
375 EXPECT_EQ(4U, File
->getSwiftABIVersion());
378 TEST(TBDv3
, Swift_4_0
) {
379 static const char tbd_v1_swift_4_0
[] = "--- !tapi-tbd-v3\n"
382 "install-name: Test.dylib\n"
383 "swift-abi-version: 4.0\n"
387 TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_4_0
, "Test.tbd"));
388 EXPECT_FALSE(!!Result
);
389 auto errorMessage
= toString(Result
.takeError());
390 EXPECT_EQ("malformed file\nTest.tbd:5:20: error: invalid Swift ABI "
391 "version.\nswift-abi-version: 4.0\n ^~~\n",
395 TEST(TBDv3
, Swift_5
) {
396 static const char tbd_v1_swift_5
[] = "--- !tapi-tbd-v3\n"
399 "install-name: Test.dylib\n"
400 "swift-abi-version: 5\n"
403 auto Result
= TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_5
, "Test.tbd"));
404 EXPECT_TRUE(!!Result
);
405 auto File
= std::move(Result
.get());
406 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
407 EXPECT_EQ(5U, File
->getSwiftABIVersion());
410 TEST(TBDv3
, Swift_99
) {
411 static const char tbd_v1_swift_99
[] = "--- !tapi-tbd-v3\n"
414 "install-name: Test.dylib\n"
415 "swift-abi-version: 99\n"
419 TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_99
, "Test.tbd"));
420 EXPECT_TRUE(!!Result
);
421 auto File
= std::move(Result
.get());
422 EXPECT_EQ(FileType::TBD_V3
, File
->getFileType());
423 EXPECT_EQ(99U, File
->getSwiftABIVersion());
426 TEST(TBDv3
, UnknownArchitecture
) {
427 static const char tbd_v3_file_unknown_architecture
[] =
431 "install-name: Test.dylib\n"
434 auto Result
= TextAPIReader::get(
435 MemoryBufferRef(tbd_v3_file_unknown_architecture
, "Test.tbd"));
436 EXPECT_TRUE(!!Result
);
439 TEST(TBDv3
, UnknownPlatform
) {
440 static const char tbd_v3_file_unknown_platform
[] = "--- !tapi-tbd-v3\n"
445 auto Result
= TextAPIReader::get(
446 MemoryBufferRef(tbd_v3_file_unknown_platform
, "Test.tbd"));
447 EXPECT_FALSE(!!Result
);
448 auto errorMessage
= toString(Result
.takeError());
449 EXPECT_EQ("malformed file\nTest.tbd:3:11: error: unknown platform\nplatform: "
454 TEST(TBDv3
, MalformedFile1
) {
455 static const char malformed_file1
[] = "--- !tapi-tbd-v3\n"
457 "foobar: \"Unsupported key\"\n"
461 TextAPIReader::get(MemoryBufferRef(malformed_file1
, "Test.tbd"));
462 EXPECT_FALSE(!!Result
);
463 auto errorMessage
= toString(Result
.takeError());
464 ASSERT_EQ("malformed file\nTest.tbd:2:1: error: missing required key "
465 "'platform'\narchs: [ arm64 ]\n^\n",
469 TEST(TBDv3
, MalformedFile2
) {
470 static const char malformed_file2
[] = "--- !tapi-tbd-v3\n"
473 "install-name: Test.dylib\n"
474 "foobar: \"Unsupported key\"\n"
478 TextAPIReader::get(MemoryBufferRef(malformed_file2
, "Test.tbd"));
479 EXPECT_FALSE(!!Result
);
480 auto errorMessage
= toString(Result
.takeError());
482 "malformed file\nTest.tbd:5:9: error: unknown key 'foobar'\nfoobar: "
483 "\"Unsupported key\"\n ^~~~~~~~~~~~~~~~~\n",