1 //===-- TextStubV3Tests.cpp - TBD V3 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 #include "TextStubHelpers.h"
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"
13 #include <string>
14 #include <vector>
15 
16 using namespace llvm;
17 using namespace llvm::MachO;
18 
19 static ExportedSymbol TBDv3Symbols[] = {
20     {SymbolKind::GlobalSymbol, "$ld$hide$os9.0$_sym1", false, false},
21     {SymbolKind::GlobalSymbol, "_sym1", false, false},
22     {SymbolKind::GlobalSymbol, "_sym2", false, false},
23     {SymbolKind::GlobalSymbol, "_sym3", false, false},
24     {SymbolKind::GlobalSymbol, "_sym4", false, false},
25     {SymbolKind::GlobalSymbol, "_sym5", false, false},
26     {SymbolKind::GlobalSymbol, "_tlv1", false, true},
27     {SymbolKind::GlobalSymbol, "_tlv3", false, true},
28     {SymbolKind::GlobalSymbol, "_weak1", true, false},
29     {SymbolKind::GlobalSymbol, "_weak2", true, false},
30     {SymbolKind::GlobalSymbol, "_weak3", true, false},
31     {SymbolKind::ObjectiveCClass, "class1", false, false},
32     {SymbolKind::ObjectiveCClass, "class2", false, false},
33     {SymbolKind::ObjectiveCClass, "class3", false, false},
34     {SymbolKind::ObjectiveCClassEHType, "class1", false, false},
35     {SymbolKind::ObjectiveCInstanceVariable, "class1._ivar1", false, false},
36     {SymbolKind::ObjectiveCInstanceVariable, "class1._ivar2", false, false},
37     {SymbolKind::ObjectiveCInstanceVariable, "class1._ivar3", false, false},
38 };
39 
40 namespace TBDv3 {
41 
TEST(TBDv3,ReadFile)42 TEST(TBDv3, ReadFile) {
43   static const char TBDv3File1[] =
44       "--- !tapi-tbd-v3\n"
45       "archs: [ armv7, arm64 ]\n"
46       "uuids: [ 'armv7: 00000000-0000-0000-0000-000000000000',\n"
47       "         'arm64: 11111111-1111-1111-1111-111111111111']\n"
48       "platform: ios\n"
49       "flags: [ installapi ]\n"
50       "install-name: Test.dylib\n"
51       "current-version: 2.3.4\n"
52       "compatibility-version: 1.0\n"
53       "swift-abi-version: 1.1\n"
54       "parent-umbrella: Umbrella.dylib\n"
55       "exports:\n"
56       "  - archs: [ armv7, arm64 ]\n"
57       "    allowable-clients: [ clientA ]\n"
58       "    re-exports: [ /usr/lib/libfoo.dylib ]\n"
59       "    symbols: [ _sym1, _sym2, _sym3, _sym4, $ld$hide$os9.0$_sym1 ]\n"
60       "    objc-classes: [ class1, class2 ]\n"
61       "    objc-eh-types: [ class1 ]\n"
62       "    objc-ivars: [ class1._ivar1, class1._ivar2 ]\n"
63       "    weak-def-symbols: [ _weak1, _weak2 ]\n"
64       "    thread-local-symbols: [ _tlv1, _tlv3 ]\n"
65       "  - archs: [ armv7 ]\n"
66       "    symbols: [ _sym5 ]\n"
67       "    objc-classes: [ class3 ]\n"
68       "    objc-ivars: [ class1._ivar3 ]\n"
69       "    weak-def-symbols: [ _weak3 ]\n"
70       "    thread-local-symbols: [ _tlv3 ]\n"
71       "...\n";
72 
73   Expected<TBDFile> Result =
74       TextAPIReader::get(MemoryBufferRef(TBDv3File1, "Test.tbd"));
75   EXPECT_TRUE(!!Result);
76   TBDFile File = std::move(Result.get());
77   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
78   auto Archs = AK_armv7 | AK_arm64;
79   auto Platform = PlatformKind::iOS;
80   TargetList Targets;
81   for (auto &&arch : Archs)
82     Targets.emplace_back(Target(arch, Platform));
83   EXPECT_EQ(Archs, File->getArchitectures());
84   UUIDs Uuids = {{Target(AK_armv7, PlatformKind::unknown),
85                   "00000000-0000-0000-0000-000000000000"},
86                  {Target(AK_arm64, PlatformKind::unknown),
87                   "11111111-1111-1111-1111-111111111111"}};
88   EXPECT_EQ(Uuids, File->uuids());
89   EXPECT_EQ(File->getPlatforms().size(), 1U);
90   EXPECT_EQ(Platform, *File->getPlatforms().begin());
91   EXPECT_EQ(std::string("Test.dylib"), File->getInstallName());
92   EXPECT_EQ(PackedVersion(2, 3, 4), File->getCurrentVersion());
93   EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());
94   EXPECT_EQ(2U, File->getSwiftABIVersion());
95   EXPECT_EQ(ObjCConstraintType::Retain_Release, File->getObjCConstraint());
96   EXPECT_TRUE(File->isTwoLevelNamespace());
97   EXPECT_TRUE(File->isApplicationExtensionSafe());
98   EXPECT_TRUE(File->isInstallAPI());
99   InterfaceFileRef client("clientA", Targets);
100   InterfaceFileRef reexport("/usr/lib/libfoo.dylib", Targets);
101   EXPECT_EQ(1U, File->allowableClients().size());
102   EXPECT_EQ(client, File->allowableClients().front());
103   EXPECT_EQ(1U, File->reexportedLibraries().size());
104   EXPECT_EQ(reexport, File->reexportedLibraries().front());
105 
106   ExportedSymbolSeq Exports;
107   for (const auto *Sym : File->symbols()) {
108     EXPECT_FALSE(Sym->isWeakReferenced());
109     EXPECT_FALSE(Sym->isUndefined());
110     Exports.emplace_back(
111         ExportedSymbol{Sym->getKind(), std::string(Sym->getName()),
112                        Sym->isWeakDefined(), Sym->isThreadLocalValue()});
113   }
114   llvm::sort(Exports.begin(), Exports.end());
115 
116   EXPECT_EQ(sizeof(TBDv3Symbols) / sizeof(ExportedSymbol), Exports.size());
117   EXPECT_TRUE(
118       std::equal(Exports.begin(), Exports.end(), std::begin(TBDv3Symbols)));
119 }
120 
TEST(TBDv3,ReadMultipleDocuments)121 TEST(TBDv3, ReadMultipleDocuments) {
122   static const char TBDv3Inlines[] =
123       "--- !tapi-tbd-v3\n"
124       "archs: [ armv7, arm64 ]\n"
125       "uuids: [ 'armv7: 00000000-0000-0000-0000-000000000000',\n"
126       "         'arm64: 11111111-1111-1111-1111-111111111111']\n"
127       "platform: ios\n"
128       "install-name: Test.dylib\n"
129       "current-version: 2.3.4\n"
130       "compatibility-version: 1.0\n"
131       "swift-abi-version: 1.1\n"
132       "parent-umbrella: Umbrella.dylib\n"
133       "exports:\n"
134       "  - archs: [ armv7, arm64 ]\n"
135       "    allowable-clients: [ clientA ]\n"
136       "    re-exports: [ /usr/lib/libfoo.dylib,\n"
137       "                  TestInline.dylib ]\n"
138       "    symbols: [ _sym1, _sym2, _sym3, _sym4, $ld$hide$os9.0$_sym1 ]\n"
139       "    objc-classes: [ class1, class2 ]\n"
140       "    objc-eh-types: [ class1 ]\n"
141       "    objc-ivars: [ class1._ivar1, class1._ivar2 ]\n"
142       "    weak-def-symbols: [ _weak1, _weak2 ]\n"
143       "    thread-local-symbols: [ _tlv1, _tlv3 ]\n"
144       "  - archs: [ armv7 ]\n"
145       "    symbols: [ _sym5 ]\n"
146       "    objc-classes: [ class3 ]\n"
147       "    objc-ivars: [ class1._ivar3 ]\n"
148       "    weak-def-symbols: [ _weak3 ]\n"
149       "    thread-local-symbols: [ _tlv3 ]\n"
150       "--- !tapi-tbd-v3\n"
151       "archs: [ armv7, arm64 ]\n"
152       "uuids: [ 'armv7: 00000000-0000-0000-0000-000000000000',\n"
153       "         'arm64: 11111111-1111-1111-1111-111111111111']\n"
154       "platform: ios\n"
155       "install-name: TestInline.dylib\n"
156       "swift-abi-version: 1.1\n"
157       "exports:\n"
158       "  - archs: [ armv7, arm64 ]\n"
159       "    symbols: [ _sym5, _sym6 ]\n"
160       "...\n";
161 
162   Expected<TBDFile> Result =
163       TextAPIReader::get(MemoryBufferRef(TBDv3Inlines, "Test.tbd"));
164   EXPECT_TRUE(!!Result);
165   TBDFile File = std::move(Result.get());
166   EXPECT_EQ(File->documents().size(), 1U);
167   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
168   auto Archs = AK_armv7 | AK_arm64;
169   auto Platform = PlatformKind::iOS;
170   TargetList Targets;
171   for (auto &&arch : Archs)
172     Targets.emplace_back(Target(arch, Platform));
173   EXPECT_EQ(Archs, File->getArchitectures());
174   UUIDs Uuids = {{Target(AK_armv7, PlatformKind::unknown),
175                   "00000000-0000-0000-0000-000000000000"},
176                  {Target(AK_arm64, PlatformKind::unknown),
177                   "11111111-1111-1111-1111-111111111111"}};
178   EXPECT_EQ(Uuids, File->uuids());
179   EXPECT_EQ(File->getPlatforms().size(), 1U);
180   EXPECT_EQ(Platform, *File->getPlatforms().begin());
181   EXPECT_EQ(std::string("Test.dylib"), File->getInstallName());
182   EXPECT_EQ(PackedVersion(2, 3, 4), File->getCurrentVersion());
183   EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());
184   EXPECT_EQ(2U, File->getSwiftABIVersion());
185   EXPECT_EQ(ObjCConstraintType::Retain_Release, File->getObjCConstraint());
186   EXPECT_TRUE(File->isTwoLevelNamespace());
187   EXPECT_TRUE(File->isApplicationExtensionSafe());
188   EXPECT_FALSE(File->isInstallAPI());
189   InterfaceFileRef Client("clientA", Targets);
190   const std::vector<InterfaceFileRef> Reexports = {
191       InterfaceFileRef("/usr/lib/libfoo.dylib", Targets),
192       InterfaceFileRef("TestInline.dylib", Targets)};
193   EXPECT_EQ(1U, File->allowableClients().size());
194   EXPECT_EQ(Client, File->allowableClients().front());
195   EXPECT_EQ(2U, File->reexportedLibraries().size());
196   EXPECT_EQ(Reexports, File->reexportedLibraries());
197 
198   ExportedSymbolSeq Exports;
199   for (const auto *Sym : File->symbols()) {
200     EXPECT_FALSE(Sym->isWeakReferenced());
201     EXPECT_FALSE(Sym->isUndefined());
202     Exports.emplace_back(ExportedSymbol{Sym->getKind(), Sym->getName().str(),
203                                         Sym->isWeakDefined(),
204                                         Sym->isThreadLocalValue()});
205   }
206   llvm::sort(Exports.begin(), Exports.end());
207 
208   EXPECT_EQ(sizeof(TBDv3Symbols) / sizeof(ExportedSymbol), Exports.size());
209   EXPECT_TRUE(
210       std::equal(Exports.begin(), Exports.end(), std::begin(TBDv3Symbols)));
211 
212   // Check Second Document
213   Exports.clear();
214   TBDReexportFile Document = File->documents().front();
215   EXPECT_EQ(FileType::TBD_V3, Document->getFileType());
216   EXPECT_EQ(Archs, Document->getArchitectures());
217   EXPECT_EQ(Uuids, Document->uuids());
218   EXPECT_EQ(Platform, *Document->getPlatforms().begin());
219   EXPECT_EQ(std::string("TestInline.dylib"), Document->getInstallName());
220   EXPECT_EQ(PackedVersion(1, 0, 0), Document->getCurrentVersion());
221   EXPECT_EQ(PackedVersion(1, 0, 0), Document->getCompatibilityVersion());
222   EXPECT_EQ(2U, Document->getSwiftABIVersion());
223 
224   for (const auto *Sym : Document->symbols()) {
225     EXPECT_FALSE(Sym->isWeakReferenced());
226     EXPECT_FALSE(Sym->isUndefined());
227     Exports.emplace_back(ExportedSymbol{Sym->getKind(), Sym->getName().str(),
228                                         Sym->isWeakDefined(),
229                                         Sym->isThreadLocalValue()});
230   }
231   llvm::sort(Exports.begin(), Exports.end());
232 
233   ExportedSymbolSeq DocumentSymbols{
234       {SymbolKind::GlobalSymbol, "_sym5", false, false},
235       {SymbolKind::GlobalSymbol, "_sym6", false, false},
236   };
237 
238   EXPECT_EQ(DocumentSymbols.size(), Exports.size());
239   EXPECT_TRUE(
240       std::equal(Exports.begin(), Exports.end(), DocumentSymbols.begin()));
241 }
242 
TEST(TBDv3,WriteFile)243 TEST(TBDv3, WriteFile) {
244   static const char TBDv3File3[] =
245       "--- !tapi-tbd-v3\n"
246       "archs:           [ i386, x86_64 ]\n"
247       "platform:        macosx\n"
248       "install-name:    '/usr/lib/libfoo.dylib'\n"
249       "current-version: 1.2.3\n"
250       "compatibility-version: 0\n"
251       "swift-abi-version: 5\n"
252       "exports:\n"
253       "  - archs:           [ i386 ]\n"
254       "    symbols:         [ _sym1 ]\n"
255       "    weak-def-symbols: [ _sym2 ]\n"
256       "    thread-local-symbols: [ _sym3 ]\n"
257       "  - archs:           [ x86_64 ]\n"
258       "    allowable-clients: [ clientA ]\n"
259       "    re-exports:      [ '/usr/lib/libfoo.dylib' ]\n"
260       "    objc-classes:    [ Class1 ]\n"
261       "    objc-eh-types:   [ Class1 ]\n"
262       "    objc-ivars:      [ Class1._ivar1 ]\n"
263       "...\n";
264 
265   InterfaceFile File;
266   TargetList Targets;
267   for (auto &&arch : AK_i386 | AK_x86_64)
268     Targets.emplace_back(Target(arch, PlatformKind::macOS));
269   File.setPath("libfoo.dylib");
270   File.setInstallName("/usr/lib/libfoo.dylib");
271   File.setFileType(FileType::TBD_V3);
272   File.addTargets(Targets);
273   File.setCurrentVersion(PackedVersion(1, 2, 3));
274   File.setTwoLevelNamespace();
275   File.setApplicationExtensionSafe();
276   File.setSwiftABIVersion(5);
277   File.setObjCConstraint(ObjCConstraintType::Retain_Release);
278   File.addAllowableClient("clientA", Targets[1]);
279   File.addReexportedLibrary("/usr/lib/libfoo.dylib", Targets[1]);
280   File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", {Targets[0]});
281   File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", {Targets[0]},
282                  SymbolFlags::WeakDefined);
283   File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", {Targets[0]},
284                  SymbolFlags::ThreadLocalValue);
285   File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", {Targets[1]});
286   File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", {Targets[1]});
287   File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1",
288                  {Targets[1]});
289 
290   SmallString<4096> Buffer;
291   raw_svector_ostream OS(Buffer);
292   Error Result = TextAPIWriter::writeToStream(OS, File);
293   EXPECT_FALSE(Result);
294   EXPECT_STREQ(TBDv3File3, Buffer.c_str());
295 }
296 
TEST(TBDv3,WriteMultipleDocuments)297 TEST(TBDv3, WriteMultipleDocuments) {
298   static const char TBDv3Inlines[] =
299       "--- !tapi-tbd-v3\n"
300       "archs:           [ i386, x86_64 ]\n"
301       "platform:        zippered\n"
302       "install-name:    '/usr/lib/libfoo.dylib'\n"
303       "current-version: 1.2.3\n"
304       "compatibility-version: 0\n"
305       "swift-abi-version: 5\n"
306       "exports:\n"
307       "  - archs:           [ x86_64 ]\n"
308       "    allowable-clients: [ clientA ]\n"
309       "    re-exports:      [ '/usr/lib/libbar.dylib' ]\n"
310       "  - archs:           [ i386, x86_64 ]\n"
311       "    symbols:         [ _sym1 ]\n"
312       "    objc-classes:    [ Class1 ]\n"
313       "    objc-eh-types:   [ Class1 ]\n"
314       "    objc-ivars:      [ Class1._ivar1 ]\n"
315       "    weak-def-symbols: [ _sym2 ]\n"
316       "    thread-local-symbols: [ _symA ]\n"
317       "--- !tapi-tbd-v3\n"
318       "archs:           [ i386 ]\n"
319       "platform:        macosx\n"
320       "install-name:    '/usr/lib/libbar.dylib'\n"
321       "current-version: 0\n"
322       "compatibility-version: 0\n"
323       "swift-abi-version: 5\n"
324       "objc-constraint: none\n"
325       "exports:\n"
326       "  - archs:           [ i386 ]\n"
327       "    symbols:         [ _sym3, _sym4 ]\n"
328       "...\n";
329 
330   InterfaceFile File;
331   TargetList Targets;
332   for (auto &&arch : AK_i386 | AK_x86_64) {
333     Targets.emplace_back(Target(arch, PlatformKind::macOS));
334     Targets.emplace_back(Target(arch, PlatformKind::macCatalyst));
335   }
336   File.addTargets(Targets);
337   File.setPath("libfoo.dylib");
338   File.setInstallName("/usr/lib/libfoo.dylib");
339   File.setFileType(FileType::TBD_V3);
340   File.setCurrentVersion(PackedVersion(1, 2, 3));
341   File.setTwoLevelNamespace();
342   File.setApplicationExtensionSafe();
343   File.setSwiftABIVersion(5);
344   File.setObjCConstraint(ObjCConstraintType::Retain_Release);
345   File.addAllowableClient("clientA", Targets[2]);
346   File.addReexportedLibrary("/usr/lib/libbar.dylib", Targets[2]);
347   File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", Targets);
348   File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", Targets,
349                  SymbolFlags::WeakDefined);
350   File.addSymbol(SymbolKind::GlobalSymbol, "_symA", Targets,
351                  SymbolFlags::ThreadLocalValue);
352   File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", Targets);
353   File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", Targets);
354   File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1",
355                  Targets);
356 
357   // Inline document
358   InterfaceFile Document;
359   Targets = {Target(AK_i386, PlatformKind::macOS)};
360   Document.addTargets(Targets);
361   Document.setPath("libbar.dylib");
362   Document.setInstallName("/usr/lib/libbar.dylib");
363   Document.setFileType(FileType::TBD_V3);
364   Document.setTwoLevelNamespace();
365   Document.setApplicationExtensionSafe();
366   Document.setSwiftABIVersion(5);
367   Document.addSymbol(SymbolKind::GlobalSymbol, "_sym3", Targets);
368   Document.addSymbol(SymbolKind::GlobalSymbol, "_sym4", Targets);
369   File.addDocument(std::make_shared<InterfaceFile>(std::move(Document)));
370 
371   SmallString<4096> Buffer;
372   raw_svector_ostream OS(Buffer);
373   Error Result = TextAPIWriter::writeToStream(OS, File);
374   EXPECT_FALSE(Result);
375   EXPECT_STREQ(TBDv3Inlines, Buffer.c_str());
376 }
377 
TEST(TBDv3,Platform_macOS)378 TEST(TBDv3, Platform_macOS) {
379   static const char TBDv3PlatformMacOS[] = "--- !tapi-tbd-v3\n"
380                                            "archs: [ x86_64 ]\n"
381                                            "platform: macosx\n"
382                                            "install-name: Test.dylib\n"
383                                            "...\n";
384 
385   Expected<TBDFile> Result =
386       TextAPIReader::get(MemoryBufferRef(TBDv3PlatformMacOS, "Test.tbd"));
387   EXPECT_TRUE(!!Result);
388   auto Platform = PlatformKind::macOS;
389   TBDFile File = std::move(Result.get());
390   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
391   EXPECT_EQ(File->getPlatforms().size(), 1U);
392   EXPECT_EQ(Platform, *File->getPlatforms().begin());
393 
394   SmallString<4096> Buffer;
395   raw_svector_ostream OS(Buffer);
396   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
397   EXPECT_TRUE(!WriteResult);
398   EXPECT_EQ(stripWhitespace(TBDv3PlatformMacOS),
399             stripWhitespace(Buffer.c_str()));
400 }
401 
TEST(TBDv3,Platform_iOS)402 TEST(TBDv3, Platform_iOS) {
403   static const char TBDv3PlatformiOS[] = "--- !tapi-tbd-v3\n"
404                                          "archs: [ arm64 ]\n"
405                                          "platform: ios\n"
406                                          "install-name: Test.dylib\n"
407                                          "...\n";
408 
409   Expected<TBDFile> Result =
410       TextAPIReader::get(MemoryBufferRef(TBDv3PlatformiOS, "Test.tbd"));
411   EXPECT_TRUE(!!Result);
412   auto Platform = PlatformKind::iOS;
413   TBDFile File = std::move(Result.get());
414   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
415   EXPECT_EQ(File->getPlatforms().size(), 1U);
416   EXPECT_EQ(Platform, *File->getPlatforms().begin());
417 
418   SmallString<4096> Buffer;
419   raw_svector_ostream OS(Buffer);
420   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
421   EXPECT_TRUE(!WriteResult);
422   EXPECT_EQ(stripWhitespace(TBDv3PlatformiOS), stripWhitespace(Buffer.c_str()));
423 }
424 
TEST(TBDv3,Platform_watchOS)425 TEST(TBDv3, Platform_watchOS) {
426   static const char TBDv3watchOS[] = "--- !tapi-tbd-v3\n"
427                                      "archs: [ armv7k ]\n"
428                                      "platform: watchos\n"
429                                      "install-name: Test.dylib\n"
430                                      "...\n";
431 
432   Expected<TBDFile> Result =
433       TextAPIReader::get(MemoryBufferRef(TBDv3watchOS, "Test.tbd"));
434   EXPECT_TRUE(!!Result);
435   auto Platform = PlatformKind::watchOS;
436   TBDFile File = std::move(Result.get());
437   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
438   EXPECT_EQ(File->getPlatforms().size(), 1U);
439   EXPECT_EQ(Platform, *File->getPlatforms().begin());
440 
441   SmallString<4096> Buffer;
442   raw_svector_ostream OS(Buffer);
443   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
444   EXPECT_TRUE(!WriteResult);
445   EXPECT_EQ(stripWhitespace(TBDv3watchOS), stripWhitespace(Buffer.c_str()));
446 }
447 
TEST(TBDv3,Platform_tvOS)448 TEST(TBDv3, Platform_tvOS) {
449   static const char TBDv3PlatformtvOS[] = "--- !tapi-tbd-v3\n"
450                                           "archs: [ arm64 ]\n"
451                                           "platform: tvos\n"
452                                           "install-name: Test.dylib\n"
453                                           "...\n";
454 
455   Expected<TBDFile> Result =
456       TextAPIReader::get(MemoryBufferRef(TBDv3PlatformtvOS, "Test.tbd"));
457   EXPECT_TRUE(!!Result);
458   TBDFile File = std::move(Result.get());
459   auto Platform = PlatformKind::tvOS;
460   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
461   EXPECT_EQ(File->getPlatforms().size(), 1U);
462   EXPECT_EQ(Platform, *File->getPlatforms().begin());
463 
464   SmallString<4096> Buffer;
465   raw_svector_ostream OS(Buffer);
466   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
467   EXPECT_FALSE(WriteResult);
468   EXPECT_EQ(stripWhitespace(TBDv3PlatformtvOS),
469             stripWhitespace(Buffer.c_str()));
470 }
471 
TEST(TBDv3,Platform_bridgeOS)472 TEST(TBDv3, Platform_bridgeOS) {
473   static const char TBDv3BridgeOS[] = "--- !tapi-tbd-v3\n"
474                                       "archs: [ armv7k ]\n"
475                                       "platform: bridgeos\n"
476                                       "install-name: Test.dylib\n"
477                                       "...\n";
478 
479   Expected<TBDFile> Result =
480       TextAPIReader::get(MemoryBufferRef(TBDv3BridgeOS, "Test.tbd"));
481   EXPECT_TRUE(!!Result);
482   auto Platform = PlatformKind::bridgeOS;
483   TBDFile File = std::move(Result.get());
484   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
485   EXPECT_EQ(File->getPlatforms().size(), 1U);
486   EXPECT_EQ(Platform, *File->getPlatforms().begin());
487 
488   SmallString<4096> Buffer;
489   raw_svector_ostream OS(Buffer);
490   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
491   EXPECT_TRUE(!WriteResult);
492   EXPECT_EQ(stripWhitespace(TBDv3BridgeOS), stripWhitespace(Buffer.c_str()));
493 }
494 
TEST(TBDv3,Platform_macCatalyst)495 TEST(TBDv3, Platform_macCatalyst) {
496   static const char TBDv3PlatformiOSmac[] = "--- !tapi-tbd-v3\n"
497                                             "archs: [ armv7k ]\n"
498                                             "platform: iosmac\n"
499                                             "install-name: Test.dylib\n"
500                                             "...\n";
501 
502   Expected<TBDFile> Result =
503       TextAPIReader::get(MemoryBufferRef(TBDv3PlatformiOSmac, "Test.tbd"));
504   EXPECT_TRUE(!!Result);
505   auto Platform = PlatformKind::macCatalyst;
506   TBDFile File = std::move(Result.get());
507   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
508   EXPECT_EQ(Platform, *File->getPlatforms().begin());
509 
510   SmallString<4096> Buffer;
511   raw_svector_ostream OS(Buffer);
512   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
513   EXPECT_TRUE(!WriteResult);
514   EXPECT_EQ(stripWhitespace(TBDv3PlatformiOSmac),
515             stripWhitespace(Buffer.c_str()));
516 }
517 
TEST(TBDv3,Platform_zippered)518 TEST(TBDv3, Platform_zippered) {
519   static const char TBDv3PlatformZippered[] = "--- !tapi-tbd-v3\n"
520                                               "archs: [ armv7k ]\n"
521                                               "platform: zippered\n"
522                                               "install-name: Test.dylib\n"
523                                               "...\n";
524 
525   Expected<TBDFile> Result =
526       TextAPIReader::get(MemoryBufferRef(TBDv3PlatformZippered, "Test.tbd"));
527   EXPECT_TRUE(!!Result);
528   TBDFile File = std::move(Result.get());
529   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
530 
531   PlatformSet Platforms;
532   Platforms.insert(PlatformKind::macOS);
533   Platforms.insert(PlatformKind::macCatalyst);
534   EXPECT_EQ(Platforms.size(), File->getPlatforms().size());
535   for (auto Platform : File->getPlatforms())
536 	    EXPECT_EQ(Platforms.count(Platform), 1U);
537 
538   SmallString<4096> Buffer;
539   raw_svector_ostream OS(Buffer);
540   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
541   EXPECT_TRUE(!WriteResult);
542   EXPECT_EQ(stripWhitespace(TBDv3PlatformZippered),
543             stripWhitespace(Buffer.c_str()));
544 }
545 
TEST(TBDv3,Platform_iOSSim)546 TEST(TBDv3, Platform_iOSSim) {
547   static const char TBDv3PlatformiOSsim[] = "--- !tapi-tbd-v3\n"
548                                             "archs: [ x86_64 ]\n"
549                                             "platform: ios\n"
550                                             "install-name: Test.dylib\n"
551                                             "...\n";
552 
553   Expected<TBDFile> Result =
554       TextAPIReader::get(MemoryBufferRef(TBDv3PlatformiOSsim, "Test.tbd"));
555   EXPECT_TRUE(!!Result);
556   auto Platform = PlatformKind::iOSSimulator;
557   TBDFile File = std::move(Result.get());
558   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
559   EXPECT_EQ(File->getPlatforms().size(), 1U);
560   EXPECT_EQ(Platform, *File->getPlatforms().begin());
561 
562   SmallString<4096> Buffer;
563   raw_svector_ostream OS(Buffer);
564   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
565   EXPECT_TRUE(!WriteResult);
566   EXPECT_EQ(stripWhitespace(TBDv3PlatformiOSsim),
567             stripWhitespace(Buffer.c_str()));
568 }
569 
TEST(TBDv3,Platform_watchOSSim)570 TEST(TBDv3, Platform_watchOSSim) {
571   static const char TBDv3watchOSsim[] = "--- !tapi-tbd-v3\n"
572                                         "archs: [ x86_64 ]\n"
573                                         "platform: watchos\n"
574                                         "install-name: Test.dylib\n"
575                                         "...\n";
576 
577   Expected<TBDFile> Result =
578       TextAPIReader::get(MemoryBufferRef(TBDv3watchOSsim, "Test.tbd"));
579   EXPECT_TRUE(!!Result);
580   auto Platform = PlatformKind::watchOSSimulator;
581   TBDFile File = std::move(Result.get());
582   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
583   EXPECT_EQ(File->getPlatforms().size(), 1U);
584   EXPECT_EQ(Platform, *File->getPlatforms().begin());
585 
586   SmallString<4096> Buffer;
587   raw_svector_ostream OS(Buffer);
588   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
589   EXPECT_TRUE(!WriteResult);
590   EXPECT_EQ(stripWhitespace(TBDv3watchOSsim), stripWhitespace(Buffer.c_str()));
591 }
592 
TEST(TBDv3,Platform_tvOSSim)593 TEST(TBDv3, Platform_tvOSSim) {
594   static const char TBDv3PlatformtvOSsim[] = "--- !tapi-tbd-v3\n"
595                                              "archs: [ x86_64 ]\n"
596                                              "platform: tvos\n"
597                                              "install-name: Test.dylib\n"
598                                              "...\n";
599 
600   Expected<TBDFile> Result =
601       TextAPIReader::get(MemoryBufferRef(TBDv3PlatformtvOSsim, "Test.tbd"));
602   EXPECT_TRUE(!!Result);
603   TBDFile File = std::move(Result.get());
604   auto Platform = PlatformKind::tvOSSimulator;
605   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
606   EXPECT_EQ(File->getPlatforms().size(), 1U);
607   EXPECT_EQ(Platform, *File->getPlatforms().begin());
608 
609   SmallString<4096> Buffer;
610   raw_svector_ostream OS(Buffer);
611   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
612   EXPECT_TRUE(!WriteResult);
613   EXPECT_EQ(stripWhitespace(TBDv3PlatformtvOSsim),
614             stripWhitespace(Buffer.c_str()));
615 }
616 
TEST(TBDv3,Arch_arm64e)617 TEST(TBDv3, Arch_arm64e) {
618   static const char TBDv3ArchArm64e[] = "--- !tapi-tbd-v3\n"
619                                         "archs: [ arm64, arm64e ]\n"
620                                         "platform: ios\n"
621                                         "install-name: Test.dylib\n"
622                                         "...\n";
623 
624   Expected<TBDFile> Result =
625       TextAPIReader::get(MemoryBufferRef(TBDv3ArchArm64e, "Test.tbd"));
626   EXPECT_TRUE(!!Result);
627   TBDFile File = std::move(Result.get());
628   auto Platform = PlatformKind::iOS;
629   auto Archs = AK_arm64 | AK_arm64e;
630   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
631   EXPECT_EQ(File->getPlatforms().size(), 1U);
632   EXPECT_EQ(Platform, *File->getPlatforms().begin());
633   EXPECT_EQ(Archs, File->getArchitectures());
634 
635   SmallString<4096> Buffer;
636   raw_svector_ostream OS(Buffer);
637   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
638   EXPECT_TRUE(!WriteResult);
639   EXPECT_EQ(stripWhitespace(TBDv3ArchArm64e), stripWhitespace(Buffer.c_str()));
640 }
641 
TEST(TBDv3,Swift_1_0)642 TEST(TBDv3, Swift_1_0) {
643   static const char TBDv3Swift1[] = "--- !tapi-tbd-v3\n"
644                                     "archs: [ arm64 ]\n"
645                                     "platform: ios\n"
646                                     "install-name: Test.dylib\n"
647                                     "swift-abi-version: 1.0\n"
648                                     "...\n";
649 
650   Expected<TBDFile> Result =
651       TextAPIReader::get(MemoryBufferRef(TBDv3Swift1, "Test.tbd"));
652   EXPECT_TRUE(!!Result);
653   TBDFile File = std::move(Result.get());
654   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
655   EXPECT_EQ(1U, File->getSwiftABIVersion());
656 
657   SmallString<4096> Buffer;
658   raw_svector_ostream OS(Buffer);
659   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
660   EXPECT_TRUE(!WriteResult);
661   EXPECT_EQ(stripWhitespace(TBDv3Swift1), stripWhitespace(Buffer.c_str()));
662 }
663 
TEST(TBDv3,Swift_1_1)664 TEST(TBDv3, Swift_1_1) {
665   static const char TBDv3Swift1Dot[] = "--- !tapi-tbd-v3\n"
666                                        "archs: [ arm64 ]\n"
667                                        "platform: ios\n"
668                                        "install-name: Test.dylib\n"
669                                        "swift-abi-version: 1.1\n"
670                                        "...\n";
671 
672   Expected<TBDFile> Result =
673       TextAPIReader::get(MemoryBufferRef(TBDv3Swift1Dot, "Test.tbd"));
674   EXPECT_TRUE(!!Result);
675   TBDFile File = std::move(Result.get());
676   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
677   EXPECT_EQ(2U, File->getSwiftABIVersion());
678 
679   SmallString<4096> Buffer;
680   raw_svector_ostream OS(Buffer);
681   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
682   EXPECT_TRUE(!WriteResult);
683   EXPECT_EQ(stripWhitespace(TBDv3Swift1Dot), stripWhitespace(Buffer.c_str()));
684 }
685 
TEST(TBDv3,Swift_2_0)686 TEST(TBDv3, Swift_2_0) {
687   static const char TBDv3Swift2[] = "--- !tapi-tbd-v3\n"
688                                     "archs: [ arm64 ]\n"
689                                     "platform: ios\n"
690                                     "install-name: Test.dylib\n"
691                                     "swift-abi-version: 2.0\n"
692                                     "...\n";
693 
694   Expected<TBDFile> Result =
695       TextAPIReader::get(MemoryBufferRef(TBDv3Swift2, "Test.tbd"));
696   EXPECT_TRUE(!!Result);
697   TBDFile File = std::move(Result.get());
698   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
699   EXPECT_EQ(3U, File->getSwiftABIVersion());
700 
701   SmallString<4096> Buffer;
702   raw_svector_ostream OS(Buffer);
703   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
704   EXPECT_TRUE(!WriteResult);
705   EXPECT_EQ(stripWhitespace(TBDv3Swift2), stripWhitespace(Buffer.c_str()));
706 }
707 
TEST(TBDv3,Swift_3_0)708 TEST(TBDv3, Swift_3_0) {
709   static const char TBDv3Swift3[] = "--- !tapi-tbd-v3\n"
710                                     "archs: [ arm64 ]\n"
711                                     "platform: ios\n"
712                                     "install-name: Test.dylib\n"
713                                     "swift-abi-version: 3.0\n"
714                                     "...\n";
715 
716   Expected<TBDFile> Result =
717       TextAPIReader::get(MemoryBufferRef(TBDv3Swift3, "Test.tbd"));
718   EXPECT_TRUE(!!Result);
719   TBDFile File = std::move(Result.get());
720   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
721   EXPECT_EQ(4U, File->getSwiftABIVersion());
722 
723   SmallString<4096> Buffer;
724   raw_svector_ostream OS(Buffer);
725   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
726   EXPECT_TRUE(!WriteResult);
727   EXPECT_EQ(stripWhitespace(TBDv3Swift3), stripWhitespace(Buffer.c_str()));
728 }
729 
TEST(TBDv3,Swift_4_0)730 TEST(TBDv3, Swift_4_0) {
731   static const char TBDv3Swift4[] = "--- !tapi-tbd-v3\n"
732                                     "archs: [ arm64 ]\n"
733                                     "platform: ios\n"
734                                     "install-name: Test.dylib\n"
735                                     "swift-abi-version: 4.0\n"
736                                     "...\n";
737 
738   Expected<TBDFile> Result =
739       TextAPIReader::get(MemoryBufferRef(TBDv3Swift4, "Test.tbd"));
740   EXPECT_FALSE(!!Result);
741   std::string ErrorMessage = toString(Result.takeError());
742   EXPECT_EQ("malformed file\nTest.tbd:5:20: error: invalid Swift ABI "
743             "version.\nswift-abi-version: 4.0\n                   ^~~\n",
744             ErrorMessage);
745 }
746 
TEST(TBDv3,Swift_5)747 TEST(TBDv3, Swift_5) {
748   static const char TBDv3Swift5[] = "--- !tapi-tbd-v3\n"
749                                     "archs: [ arm64 ]\n"
750                                     "platform: ios\n"
751                                     "install-name: Test.dylib\n"
752                                     "swift-abi-version: 5\n"
753                                     "...\n";
754 
755   Expected<TBDFile> Result =
756       TextAPIReader::get(MemoryBufferRef(TBDv3Swift5, "Test.tbd"));
757   EXPECT_TRUE(!!Result);
758   TBDFile File = std::move(Result.get());
759   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
760   EXPECT_EQ(5U, File->getSwiftABIVersion());
761 }
762 
TEST(TBDv3,Swift_99)763 TEST(TBDv3, Swift_99) {
764   static const char TBDv3Swift99[] = "--- !tapi-tbd-v3\n"
765                                      "archs: [ arm64 ]\n"
766                                      "platform: ios\n"
767                                      "install-name: Test.dylib\n"
768                                      "swift-abi-version: 99\n"
769                                      "...\n";
770 
771   Expected<TBDFile> Result =
772       TextAPIReader::get(MemoryBufferRef(TBDv3Swift99, "Test.tbd"));
773   EXPECT_TRUE(!!Result);
774   TBDFile File = std::move(Result.get());
775   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
776   EXPECT_EQ(99U, File->getSwiftABIVersion());
777 }
778 
TEST(TBDv3,UnknownArchitecture)779 TEST(TBDv3, UnknownArchitecture) {
780   static const char TBDv3FileUnknownArch[] = "--- !tapi-tbd-v3\n"
781                                              "archs: [ foo ]\n"
782                                              "platform: macosx\n"
783                                              "install-name: Test.dylib\n"
784                                              "...\n";
785 
786   Expected<TBDFile> Result =
787       TextAPIReader::get(MemoryBufferRef(TBDv3FileUnknownArch, "Test.tbd"));
788   EXPECT_TRUE(!!Result);
789 }
790 
TEST(TBDv3,UnknownPlatform)791 TEST(TBDv3, UnknownPlatform) {
792   static const char TBDv3FileUnknownPlatform[] = "--- !tapi-tbd-v3\n"
793                                                  "archs: [ i386 ]\n"
794                                                  "platform: newOS\n"
795                                                  "...\n";
796 
797   Expected<TBDFile> Result =
798       TextAPIReader::get(MemoryBufferRef(TBDv3FileUnknownPlatform, "Test.tbd"));
799   EXPECT_FALSE(!!Result);
800   std::string ErrorMessage = toString(Result.takeError());
801   EXPECT_EQ("malformed file\nTest.tbd:3:11: error: unknown platform\nplatform: "
802             "newOS\n          ^~~~~\n",
803             ErrorMessage);
804 }
805 
TEST(TBDv3,MalformedFile1)806 TEST(TBDv3, MalformedFile1) {
807   static const char TBDv3FileMalformed1[] = "--- !tapi-tbd-v3\n"
808                                             "archs: [ arm64 ]\n"
809                                             "foobar: \"Unsupported key\"\n"
810                                             "...\n";
811 
812   Expected<TBDFile> Result =
813       TextAPIReader::get(MemoryBufferRef(TBDv3FileMalformed1, "Test.tbd"));
814   EXPECT_FALSE(!!Result);
815   std::string ErrorMessage = toString(Result.takeError());
816   ASSERT_EQ("malformed file\nTest.tbd:2:1: error: missing required key "
817             "'platform'\narchs: [ arm64 ]\n^\n",
818             ErrorMessage);
819 }
820 
TEST(TBDv3,MalformedFile2)821 TEST(TBDv3, MalformedFile2) {
822   static const char TBDv3FileMalformed2[] = "--- !tapi-tbd-v3\n"
823                                             "archs: [ arm64 ]\n"
824                                             "platform: ios\n"
825                                             "install-name: Test.dylib\n"
826                                             "foobar: \"Unsupported key\"\n"
827                                             "...\n";
828 
829   Expected<TBDFile> Result =
830       TextAPIReader::get(MemoryBufferRef(TBDv3FileMalformed2, "Test.tbd"));
831   EXPECT_FALSE(!!Result);
832   std::string ErrorMessage = toString(Result.takeError());
833   ASSERT_EQ(
834       "malformed file\nTest.tbd:5:9: error: unknown key 'foobar'\nfoobar: "
835       "\"Unsupported key\"\n        ^~~~~~~~~~~~~~~~~\n",
836       ErrorMessage);
837 }
838 
839 } // namespace TBDv3
840