xref: /llvm-project/llvm/unittests/TextAPI/TextStubV4Tests.cpp (revision fd4d07517b2c94e4ca2a855a78b38953cc9d31e1)
1 //===-- TextStubV4Tests.cpp - TBD V4 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/MachO/InterfaceFile.h"
11 #include "llvm/TextAPI/MachO/TextAPIReader.h"
12 #include "llvm/TextAPI/MachO/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 
21 namespace TBDv4 {
22 
23 TEST(TBDv4, ReadFile) {
24   static const char TBDv4File[] =
25       "--- !tapi-tbd\n"
26       "tbd-version: 4\n"
27       "targets:  [ i386-macos, x86_64-macos, x86_64-ios ]\n"
28       "uuids:\n"
29       "  - target: i386-macos\n"
30       "    value: 00000000-0000-0000-0000-000000000000\n"
31       "  - target: x86_64-macos\n"
32       "    value: 11111111-1111-1111-1111-111111111111\n"
33       "  - target: x86_64-ios\n"
34       "    value: 11111111-1111-1111-1111-111111111111\n"
35       "flags: [ flat_namespace, installapi ]\n"
36       "install-name: Umbrella.framework/Umbrella\n"
37       "current-version: 1.2.3\n"
38       "compatibility-version: 1.2\n"
39       "swift-abi-version: 5\n"
40       "parent-umbrella:\n"
41       "  - targets: [ i386-macos, x86_64-macos, x86_64-ios ]\n"
42       "    umbrella: System\n"
43       "allowable-clients:\n"
44       "  - targets: [ i386-macos, x86_64-macos, x86_64-ios ]\n"
45       "    clients: [ ClientA ]\n"
46       "reexported-libraries:\n"
47       "  - targets: [ i386-macos ]\n"
48       "    libraries: [ /System/Library/Frameworks/A.framework/A ]\n"
49       "exports:\n"
50       "  - targets: [ i386-macos ]\n"
51       "    symbols: [ _symA ]\n"
52       "    objc-classes: []\n"
53       "    objc-eh-types: []\n"
54       "    objc-ivars: []\n"
55       "    weak-symbols: []\n"
56       "    thread-local-symbols: []\n"
57       "  - targets: [ x86_64-ios ]\n"
58       "    symbols: [_symB]\n"
59       "  - targets: [ x86_64-macos, x86_64-ios ]\n"
60       "    symbols: [_symAB]\n"
61       "reexports:\n"
62       "  - targets: [ i386-macos ]\n"
63       "    symbols: [_symC]\n"
64       "    objc-classes: []\n"
65       "    objc-eh-types: []\n"
66       "    objc-ivars: []\n"
67       "    weak-symbols: []\n"
68       "    thread-local-symbols: []\n"
69       "undefineds:\n"
70       "  - targets: [ i386-macos ]\n"
71       "    symbols: [ _symD ]\n"
72       "    objc-classes: []\n"
73       "    objc-eh-types: []\n"
74       "    objc-ivars: []\n"
75       "    weak-symbols: []\n"
76       "    thread-local-symbols: []\n"
77       "...\n";
78 
79   auto Result = TextAPIReader::get(MemoryBufferRef(TBDv4File, "Test.tbd"));
80   EXPECT_TRUE(!!Result);
81   auto File = std::move(Result.get());
82   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
83   PlatformSet Platforms;
84   Platforms.insert(PlatformKind::macOS);
85   Platforms.insert(PlatformKind::iOS);
86   auto Archs = AK_i386 | AK_x86_64;
87   TargetList Targets = {
88       Target(AK_i386, PlatformKind::macOS),
89       Target(AK_x86_64, PlatformKind::macOS),
90       Target(AK_x86_64, PlatformKind::iOS),
91   };
92   UUIDs uuids = {{Targets[0], "00000000-0000-0000-0000-000000000000"},
93                  {Targets[1], "11111111-1111-1111-1111-111111111111"},
94                  {Targets[2], "11111111-1111-1111-1111-111111111111"}};
95   EXPECT_EQ(Archs, File->getArchitectures());
96   EXPECT_EQ(uuids, File->uuids());
97   EXPECT_EQ(Platforms.size(), File->getPlatforms().size());
98   for (auto Platform : File->getPlatforms())
99     EXPECT_EQ(Platforms.count(Platform), 1U);
100   EXPECT_EQ(std::string("Umbrella.framework/Umbrella"), File->getInstallName());
101   EXPECT_EQ(PackedVersion(1, 2, 3), File->getCurrentVersion());
102   EXPECT_EQ(PackedVersion(1, 2, 0), File->getCompatibilityVersion());
103   EXPECT_EQ(5U, File->getSwiftABIVersion());
104   EXPECT_FALSE(File->isTwoLevelNamespace());
105   EXPECT_TRUE(File->isApplicationExtensionSafe());
106   EXPECT_TRUE(File->isInstallAPI());
107   InterfaceFileRef client("ClientA", Targets);
108   InterfaceFileRef reexport("/System/Library/Frameworks/A.framework/A",
109                             {Targets[0]});
110   EXPECT_EQ(1U, File->allowableClients().size());
111   EXPECT_EQ(client, File->allowableClients().front());
112   EXPECT_EQ(1U, File->reexportedLibraries().size());
113   EXPECT_EQ(reexport, File->reexportedLibraries().front());
114 
115   ExportedSymbolSeq Exports, Reexports, Undefineds;
116   ExportedSymbol temp;
117   for (const auto *Sym : File->symbols()) {
118     temp = ExportedSymbol{Sym->getKind(), std::string(Sym->getName()),
119                           Sym->isWeakDefined(), Sym->isThreadLocalValue()};
120     EXPECT_FALSE(Sym->isWeakReferenced());
121     if (Sym->isUndefined())
122       Undefineds.emplace_back(std::move(temp));
123     else
124       Sym->isReexported() ? Reexports.emplace_back(std::move(temp))
125                           : Exports.emplace_back(std::move(temp));
126   }
127   llvm::sort(Exports.begin(), Exports.end());
128   llvm::sort(Reexports.begin(), Reexports.end());
129   llvm::sort(Undefineds.begin(), Undefineds.end());
130 
131   static ExportedSymbol ExpectedExportedSymbols[] = {
132       {SymbolKind::GlobalSymbol, "_symA", false, false},
133       {SymbolKind::GlobalSymbol, "_symAB", false, false},
134       {SymbolKind::GlobalSymbol, "_symB", false, false},
135   };
136 
137   static ExportedSymbol ExpectedReexportedSymbols[] = {
138       {SymbolKind::GlobalSymbol, "_symC", false, false},
139   };
140 
141   static ExportedSymbol ExpectedUndefinedSymbols[] = {
142       {SymbolKind::GlobalSymbol, "_symD", false, false},
143   };
144 
145   EXPECT_EQ(sizeof(ExpectedExportedSymbols) / sizeof(ExportedSymbol),
146             Exports.size());
147   EXPECT_EQ(sizeof(ExpectedReexportedSymbols) / sizeof(ExportedSymbol),
148             Reexports.size());
149   EXPECT_EQ(sizeof(ExpectedUndefinedSymbols) / sizeof(ExportedSymbol),
150             Undefineds.size());
151   EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
152                          std::begin(ExpectedExportedSymbols)));
153   EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
154                          std::begin(ExpectedReexportedSymbols)));
155   EXPECT_TRUE(std::equal(Undefineds.begin(), Undefineds.end(),
156                          std::begin(ExpectedUndefinedSymbols)));
157 }
158 
159 TEST(TBDv4, ReadMultipleDocuments) {
160   static const char TBDv4Inlines[] =
161       "--- !tapi-tbd\n"
162       "tbd-version: 4\n"
163       "targets: [ i386-macos, i386-maccatalyst, x86_64-macos, "
164       "x86_64-maccatalyst ]\n"
165       "uuids:\n"
166       "  - target: i386-macos\n"
167       "    value: 00000000-0000-0000-0000-000000000000\n"
168       "  - target: i386-maccatalyst\n"
169       "    value: 00000000-0000-0000-0000-000000000002\n"
170       "  - target: x86_64-macos\n"
171       "    value: 11111111-1111-1111-1111-111111111111\n"
172       "  - target: x86_64-maccatalyst\n"
173       "    value: 11111111-1111-1111-1111-111111111112\n"
174       "install-name: /System/Library/Frameworks/Umbrella.framework/Umbrella\n"
175       "parent-umbrella:\n"
176       "  - targets: [ i386-macos, x86_64-macos ]\n"
177       "    umbrella: System\n"
178       "reexported-libraries:\n"
179       "  - targets: [ i386-macos, x86_64-macos ]\n"
180       "    libraries: [ /System/Library/Frameworks/A.framework/A ]\n"
181       "--- !tapi-tbd\n"
182       "tbd-version: 4\n"
183       "targets:  [ i386-macos, x86_64-macos ]\n"
184       "uuids:\n"
185       "  - target: i386-macos\n"
186       "    value: 20000000-0000-0000-0000-000000000000\n"
187       "  - target: x86_64-macos\n"
188       "    value: 21111111-1111-1111-1111-111111111111\n"
189       "flags: [ flat_namespace ]\n"
190       "install-name: /System/Library/Frameworks/A.framework/A\n"
191       "current-version: 1.2.3\n"
192       "compatibility-version: 1.2\n"
193       "swift-abi-version: 5\n"
194       "exports:\n"
195       "  - targets: [ i386-macos ]\n"
196       "    symbols: [ _symA ]\n"
197       "    objc-classes: []\n"
198       "    objc-eh-types: []\n"
199       "    objc-ivars: []\n"
200       "    weak-symbols: []\n"
201       "    thread-local-symbols: []\n"
202       "  - targets: [ x86_64-macos ]\n"
203       "    symbols: [_symAB]\n"
204       "reexports:\n"
205       "  - targets: [ i386-macos ]\n"
206       "    symbols: [_symC]\n"
207       "    objc-classes: []\n"
208       "    objc-eh-types: []\n"
209       "    objc-ivars: []\n"
210       "    weak-symbols: []\n"
211       "    thread-local-symbols: []\n"
212       "undefineds:\n"
213       "  - targets: [ i386-macos ]\n"
214       "    symbols: [ _symD ]\n"
215       "    objc-classes: []\n"
216       "    objc-eh-types: []\n"
217       "    objc-ivars: []\n"
218       "    weak-symbols: []\n"
219       "    thread-local-symbols: []\n"
220       "...\n";
221 
222   PlatformSet Platforms;
223   Platforms.insert(PlatformKind::macOS);
224   Platforms.insert(PlatformKind::macCatalyst);
225   ArchitectureSet Archs = AK_i386 | AK_x86_64;
226   TargetList Targets;
227   for (auto &&Arch : Archs)
228     for (auto &&Platform : Platforms)
229       Targets.emplace_back(Target(Arch, Platform));
230   UUIDs Uuids = {
231       {Targets[0], "00000000-0000-0000-0000-000000000000"},
232       {Targets[1], "00000000-0000-0000-0000-000000000002"},
233       {Targets[2], "11111111-1111-1111-1111-111111111111"},
234       {Targets[3], "11111111-1111-1111-1111-111111111112"},
235   };
236 
237   auto Result = TextAPIReader::get(MemoryBufferRef(TBDv4Inlines, "Test.tbd"));
238   EXPECT_TRUE(!!Result);
239   auto File = std::move(Result.get());
240   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
241   EXPECT_EQ(Archs, File->getArchitectures());
242   EXPECT_EQ(Uuids, File->uuids());
243   EXPECT_EQ(Platforms, File->getPlatforms());
244   EXPECT_EQ(
245       std::string("/System/Library/Frameworks/Umbrella.framework/Umbrella"),
246       File->getInstallName());
247   EXPECT_TRUE(File->isTwoLevelNamespace());
248   EXPECT_TRUE(File->isApplicationExtensionSafe());
249   EXPECT_FALSE(File->isInstallAPI());
250   EXPECT_EQ(PackedVersion(1, 0, 0), File->getCurrentVersion());
251   EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());
252   InterfaceFileRef reexport("/System/Library/Frameworks/A.framework/A",
253                             {Targets[0], Targets[2]});
254   EXPECT_EQ(1U, File->reexportedLibraries().size());
255   EXPECT_EQ(reexport, File->reexportedLibraries().front());
256   ExportedSymbolSeq Exports;
257   for (const auto *Sym : File->symbols()) {
258     EXPECT_FALSE(Sym->isWeakReferenced());
259     EXPECT_FALSE(Sym->isUndefined());
260     Exports.emplace_back(ExportedSymbol{Sym->getKind(), Sym->getName().str(),
261                                         Sym->isWeakDefined(),
262                                         Sym->isThreadLocalValue()});
263   }
264   EXPECT_EQ(0U, Exports.size());
265 
266   // Check Inlined Document
267   Exports.clear();
268   Targets.clear();
269   Uuids.clear();
270   PlatformKind Platform = PlatformKind::macOS;
271   for (auto &&Arch : Archs)
272     Targets.emplace_back(Target(Arch, Platform));
273   Uuids = {
274       {Targets[0], "20000000-0000-0000-0000-000000000000"},
275       {Targets[1], "21111111-1111-1111-1111-111111111111"},
276   };
277 
278   auto Document = File->documents().front();
279   EXPECT_EQ(FileType::TBD_V4, Document->getFileType());
280   EXPECT_EQ(Archs, Document->getArchitectures());
281   EXPECT_EQ(Uuids, Document->uuids());
282   EXPECT_EQ(1U, Document->getPlatforms().size());
283   EXPECT_EQ(Platform, *(Document->getPlatforms().begin()));
284   EXPECT_EQ(std::string("/System/Library/Frameworks/A.framework/A"),
285             Document->getInstallName());
286   EXPECT_EQ(PackedVersion(1, 2, 3), Document->getCurrentVersion());
287   EXPECT_EQ(PackedVersion(1, 2, 0), Document->getCompatibilityVersion());
288   EXPECT_EQ(5U, Document->getSwiftABIVersion());
289   EXPECT_FALSE(Document->isTwoLevelNamespace());
290   EXPECT_TRUE(Document->isApplicationExtensionSafe());
291   EXPECT_FALSE(Document->isInstallAPI());
292 
293   ExportedSymbolSeq Reexports, Undefineds;
294   for (const auto *Sym : Document->symbols()) {
295     ExportedSymbol Temp =
296         ExportedSymbol{Sym->getKind(), std::string(Sym->getName()),
297                        Sym->isWeakDefined(), Sym->isThreadLocalValue()};
298     EXPECT_FALSE(Sym->isWeakReferenced());
299     if (Sym->isUndefined())
300       Undefineds.emplace_back(std::move(Temp));
301     else
302       Sym->isReexported() ? Reexports.emplace_back(std::move(Temp))
303                           : Exports.emplace_back(std::move(Temp));
304   }
305   llvm::sort(Exports.begin(), Exports.end());
306   llvm::sort(Reexports.begin(), Reexports.end());
307   llvm::sort(Undefineds.begin(), Undefineds.end());
308 
309   static ExportedSymbol ExpectedExportedSymbols[] = {
310       {SymbolKind::GlobalSymbol, "_symA", false, false},
311       {SymbolKind::GlobalSymbol, "_symAB", false, false},
312   };
313 
314   static ExportedSymbol ExpectedReexportedSymbols[] = {
315       {SymbolKind::GlobalSymbol, "_symC", false, false},
316   };
317 
318   static ExportedSymbol ExpectedUndefinedSymbols[] = {
319       {SymbolKind::GlobalSymbol, "_symD", false, false},
320   };
321 
322   EXPECT_EQ(sizeof(ExpectedExportedSymbols) / sizeof(ExportedSymbol),
323             Exports.size());
324   EXPECT_EQ(sizeof(ExpectedReexportedSymbols) / sizeof(ExportedSymbol),
325             Reexports.size());
326   EXPECT_EQ(sizeof(ExpectedUndefinedSymbols) / sizeof(ExportedSymbol),
327             Undefineds.size());
328   EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
329                          std::begin(ExpectedExportedSymbols)));
330   EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
331                          std::begin(ExpectedReexportedSymbols)));
332   EXPECT_TRUE(std::equal(Undefineds.begin(), Undefineds.end(),
333                          std::begin(ExpectedUndefinedSymbols)));
334 }
335 
336 TEST(TBDv4, WriteFile) {
337   static const char TBDv4File[] =
338       "--- !tapi-tbd\n"
339       "tbd-version:     4\n"
340       "targets:         [ i386-macos, x86_64-ios-simulator ]\n"
341       "uuids:\n"
342       "  - target:          i386-macos\n"
343       "    value:           00000000-0000-0000-0000-000000000000\n"
344       "  - target:          x86_64-ios-simulator\n"
345       "    value:           11111111-1111-1111-1111-111111111111\n"
346       "flags:           [ installapi ]\n"
347       "install-name:    'Umbrella.framework/Umbrella'\n"
348       "current-version: 1.2.3\n"
349       "compatibility-version: 0\n"
350       "swift-abi-version: 5\n"
351       "parent-umbrella:\n"
352       "  - targets:         [ i386-macos, x86_64-ios-simulator ]\n"
353       "    umbrella:        System\n"
354       "allowable-clients:\n"
355       "  - targets:         [ i386-macos ]\n"
356       "    clients:         [ ClientA ]\n"
357       "exports:\n"
358       "  - targets:         [ i386-macos ]\n"
359       "    symbols:         [ _symA ]\n"
360       "    objc-classes:    [ Class1 ]\n"
361       "    weak-symbols:    [ _symC ]\n"
362       "  - targets:         [ x86_64-ios-simulator ]\n"
363       "    symbols:         [ _symB ]\n"
364       "...\n";
365 
366   InterfaceFile File;
367   TargetList Targets = {
368       Target(AK_i386, PlatformKind::macOS),
369       Target(AK_x86_64, PlatformKind::iOSSimulator),
370   };
371   UUIDs uuids = {{Targets[0], "00000000-0000-0000-0000-000000000000"},
372                  {Targets[1], "11111111-1111-1111-1111-111111111111"}};
373   File.setInstallName("Umbrella.framework/Umbrella");
374   File.setFileType(FileType::TBD_V4);
375   File.addTargets(Targets);
376   File.addUUID(uuids[0].first, uuids[0].second);
377   File.addUUID(uuids[1].first, uuids[1].second);
378   File.setCurrentVersion(PackedVersion(1, 2, 3));
379   File.setTwoLevelNamespace();
380   File.setInstallAPI(true);
381   File.setApplicationExtensionSafe(true);
382   File.setSwiftABIVersion(5);
383   File.addAllowableClient("ClientA", Targets[0]);
384   File.addParentUmbrella(Targets[0], "System");
385   File.addParentUmbrella(Targets[1], "System");
386   File.addSymbol(SymbolKind::GlobalSymbol, "_symA", {Targets[0]});
387   File.addSymbol(SymbolKind::GlobalSymbol, "_symB", {Targets[1]});
388   File.addSymbol(SymbolKind::GlobalSymbol, "_symC", {Targets[0]},
389                  SymbolFlags::WeakDefined);
390   File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", {Targets[0]});
391 
392   SmallString<4096> Buffer;
393   raw_svector_ostream OS(Buffer);
394   auto Result = TextAPIWriter::writeToStream(OS, File);
395   EXPECT_FALSE(Result);
396   EXPECT_STREQ(TBDv4File, Buffer.c_str());
397 }
398 
399 TEST(TBDv4, WriteMultipleDocuments) {
400   static const char TBDv4Inlines[] =
401       "--- !tapi-tbd\n"
402       "tbd-version:     4\n"
403       "targets:         [ i386-maccatalyst, x86_64-maccatalyst ]\n"
404       "uuids:\n"
405       "  - target:          i386-maccatalyst\n"
406       "    value:           00000000-0000-0000-0000-000000000002\n"
407       "  - target:          x86_64-maccatalyst\n"
408       "    value:           11111111-1111-1111-1111-111111111112\n"
409       "install-name:    "
410       "'/System/Library/Frameworks/Umbrella.framework/Umbrella'\n"
411       "reexported-libraries:\n"
412       "  - targets:         [ i386-maccatalyst, x86_64-maccatalyst ]\n"
413       "    libraries:       [ '/System/Library/Frameworks/A.framework/A' ]\n"
414       "--- !tapi-tbd\n"
415       "tbd-version:     4\n"
416       "targets:         [ i386-maccatalyst, x86_64-maccatalyst ]\n"
417       "uuids:\n"
418       "  - target:          i386-maccatalyst\n"
419       "    value:           00000000-0000-0000-0000-000000000000\n"
420       "  - target:          x86_64-maccatalyst\n"
421       "    value:           11111111-1111-1111-1111-111111111111\n"
422       "install-name:    '/System/Library/Frameworks/A.framework/A'\n"
423       "exports:\n"
424       "  - targets:         [ i386-maccatalyst ]\n"
425       "    weak-symbols:    [ _symC ]\n"
426       "  - targets:         [ i386-maccatalyst, x86_64-maccatalyst ]\n"
427       "    symbols:         [ _symA ]\n"
428       "    objc-classes:    [ Class1 ]\n"
429       "  - targets:         [ x86_64-maccatalyst ]\n"
430       "    symbols:         [ _symAB ]\n"
431       "...\n";
432 
433   InterfaceFile File;
434   PlatformKind Platform = PlatformKind::macCatalyst;
435   TargetList Targets = {
436       Target(AK_i386, Platform),
437       Target(AK_x86_64, Platform),
438   };
439   UUIDs Uuids = {{Targets[0], "00000000-0000-0000-0000-000000000002"},
440                  {Targets[1], "11111111-1111-1111-1111-111111111112"}};
441   File.setInstallName("/System/Library/Frameworks/Umbrella.framework/Umbrella");
442   File.setFileType(FileType::TBD_V4);
443   File.addTargets(Targets);
444   File.addUUID(Uuids[0].first, Uuids[0].second);
445   File.addUUID(Uuids[1].first, Uuids[1].second);
446   File.setCompatibilityVersion(PackedVersion(1, 0, 0));
447   File.setCurrentVersion(PackedVersion(1, 0, 0));
448   File.setTwoLevelNamespace();
449   File.setApplicationExtensionSafe(true);
450   File.addReexportedLibrary("/System/Library/Frameworks/A.framework/A",
451                             Targets[0]);
452   File.addReexportedLibrary("/System/Library/Frameworks/A.framework/A",
453                             Targets[1]);
454 
455   // Write Second Document
456   Uuids = {{Targets[0], "00000000-0000-0000-0000-000000000000"},
457            {Targets[1], "11111111-1111-1111-1111-111111111111"}};
458   InterfaceFile Document;
459   Document.setInstallName("/System/Library/Frameworks/A.framework/A");
460   Document.setFileType(FileType::TBD_V4);
461   Document.addTargets(Targets);
462   Document.addUUID(Uuids[0].first, Uuids[0].second);
463   Document.addUUID(Uuids[1].first, Uuids[1].second);
464   Document.setCompatibilityVersion(PackedVersion(1, 0, 0));
465   Document.setCurrentVersion(PackedVersion(1, 0, 0));
466   Document.setTwoLevelNamespace();
467   Document.setApplicationExtensionSafe(true);
468   Document.addSymbol(SymbolKind::GlobalSymbol, "_symA", Targets);
469   Document.addSymbol(SymbolKind::GlobalSymbol, "_symAB", {Targets[1]});
470   Document.addSymbol(SymbolKind::GlobalSymbol, "_symC", {Targets[0]},
471                      SymbolFlags::WeakDefined);
472   Document.addSymbol(SymbolKind::ObjectiveCClass, "Class1", Targets);
473   File.addDocument(std::make_shared<InterfaceFile>(std::move(Document)));
474 
475   SmallString<4096> Buffer;
476   raw_svector_ostream OS(Buffer);
477   auto Result = TextAPIWriter::writeToStream(OS, File);
478   EXPECT_FALSE(Result);
479   EXPECT_STREQ(TBDv4Inlines, Buffer.c_str());
480 }
481 
482 TEST(TBDv4, MultipleTargets) {
483   static const char TBDv4MultipleTargets[] =
484       "--- !tapi-tbd\n"
485       "tbd-version: 4\n"
486       "targets: [ i386-maccatalyst, x86_64-tvos, arm64-ios ]\n"
487       "install-name: Test.dylib\n"
488       "...\n";
489 
490   auto Result =
491       TextAPIReader::get(MemoryBufferRef(TBDv4MultipleTargets, "Test.tbd"));
492   EXPECT_TRUE(!!Result);
493   PlatformSet Platforms;
494   Platforms.insert(PlatformKind::macCatalyst);
495   Platforms.insert(PlatformKind::tvOS);
496   Platforms.insert(PlatformKind::iOS);
497   auto File = std::move(Result.get());
498   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
499   EXPECT_EQ(AK_x86_64 | AK_arm64 | AK_i386, File->getArchitectures());
500   EXPECT_EQ(Platforms.size(), File->getPlatforms().size());
501   for (auto Platform : File->getPlatforms())
502     EXPECT_EQ(Platforms.count(Platform), 1U);
503 
504   SmallString<4096> Buffer;
505   raw_svector_ostream OS(Buffer);
506   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
507   EXPECT_TRUE(!WriteResult);
508   EXPECT_EQ(stripWhitespace(TBDv4MultipleTargets),
509             stripWhitespace(Buffer.c_str()));
510 }
511 
512 TEST(TBDv4, MultipleTargetsSameArch) {
513   static const char TBDv4TargetsSameArch[] =
514       "--- !tapi-tbd\n"
515       "tbd-version: 4\n"
516       "targets: [ x86_64-tvos , x86_64-maccatalyst ]\n"
517       "install-name: Test.dylib\n"
518       "...\n";
519 
520   auto Result =
521       TextAPIReader::get(MemoryBufferRef(TBDv4TargetsSameArch, "Test.tbd"));
522   EXPECT_TRUE(!!Result);
523   PlatformSet Platforms;
524   Platforms.insert(PlatformKind::tvOS);
525   Platforms.insert(PlatformKind::macCatalyst);
526   auto File = std::move(Result.get());
527   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
528   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
529   EXPECT_EQ(Platforms.size(), File->getPlatforms().size());
530   for (auto Platform : File->getPlatforms())
531     EXPECT_EQ(Platforms.count(Platform), 1U);
532 
533   SmallString<4096> Buffer;
534   raw_svector_ostream OS(Buffer);
535   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
536   EXPECT_TRUE(!WriteResult);
537   EXPECT_EQ(stripWhitespace(TBDv4TargetsSameArch),
538             stripWhitespace(Buffer.c_str()));
539 }
540 
541 TEST(TBDv4, MultipleTargetsSamePlatform) {
542   static const char TBDv4MultipleTargetsSamePlatform[] =
543       "--- !tapi-tbd\n"
544       "tbd-version: 4\n"
545       "targets: [ armv7k-ios , arm64-ios]\n"
546       "install-name: Test.dylib\n"
547       "...\n";
548 
549   auto Result = TextAPIReader::get(
550       MemoryBufferRef(TBDv4MultipleTargetsSamePlatform, "Test.tbd"));
551   EXPECT_TRUE(!!Result);
552   auto File = std::move(Result.get());
553   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
554   EXPECT_EQ(AK_arm64 | AK_armv7k, File->getArchitectures());
555   EXPECT_EQ(File->getPlatforms().size(), 1U);
556   EXPECT_EQ(PlatformKind::iOS, *File->getPlatforms().begin());
557 
558   SmallString<4096> Buffer;
559   raw_svector_ostream OS(Buffer);
560   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
561   EXPECT_TRUE(!WriteResult);
562   EXPECT_EQ(stripWhitespace(TBDv4MultipleTargetsSamePlatform),
563             stripWhitespace(Buffer.c_str()));
564 }
565 
566 TEST(TBDv4, Target_maccatalyst) {
567   static const char TBDv4TargetMacCatalyst[] =
568       "--- !tapi-tbd\n"
569       "tbd-version: 4\n"
570       "targets: [  x86_64-maccatalyst ]\n"
571       "install-name: Test.dylib\n"
572       "...\n";
573 
574   auto Result =
575       TextAPIReader::get(MemoryBufferRef(TBDv4TargetMacCatalyst, "Test.tbd"));
576   EXPECT_TRUE(!!Result);
577   auto File = std::move(Result.get());
578   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
579   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
580   EXPECT_EQ(File->getPlatforms().size(), 1U);
581   EXPECT_EQ(PlatformKind::macCatalyst, *File->getPlatforms().begin());
582 
583   SmallString<4096> Buffer;
584   raw_svector_ostream OS(Buffer);
585   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
586   EXPECT_TRUE(!WriteResult);
587   EXPECT_EQ(stripWhitespace(TBDv4TargetMacCatalyst),
588             stripWhitespace(Buffer.c_str()));
589 }
590 
591 TEST(TBDv4, Target_x86_ios) {
592   static const char TBDv4Targetx86iOS[] = "--- !tapi-tbd\n"
593                                           "tbd-version: 4\n"
594                                           "targets: [  x86_64-ios ]\n"
595                                           "install-name: Test.dylib\n"
596                                           "...\n";
597 
598   auto Result =
599       TextAPIReader::get(MemoryBufferRef(TBDv4Targetx86iOS, "Test.tbd"));
600   EXPECT_TRUE(!!Result);
601   auto File = std::move(Result.get());
602   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
603   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
604   EXPECT_EQ(File->getPlatforms().size(), 1U);
605   EXPECT_EQ(PlatformKind::iOS, *File->getPlatforms().begin());
606 
607   SmallString<4096> Buffer;
608   raw_svector_ostream OS(Buffer);
609   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
610   EXPECT_TRUE(!WriteResult);
611   EXPECT_EQ(stripWhitespace(TBDv4Targetx86iOS),
612             stripWhitespace(Buffer.c_str()));
613 }
614 
615 TEST(TBDv4, Target_arm_bridgeOS) {
616   static const char TBDv4PlatformBridgeOS[] = "--- !tapi-tbd\n"
617                                               "tbd-version: 4\n"
618                                               "targets: [  armv7k-bridgeos ]\n"
619                                               "install-name: Test.dylib\n"
620                                               "...\n";
621 
622   auto Result =
623       TextAPIReader::get(MemoryBufferRef(TBDv4PlatformBridgeOS, "Test.tbd"));
624   EXPECT_TRUE(!!Result);
625   auto File = std::move(Result.get());
626   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
627   EXPECT_EQ(File->getPlatforms().size(), 1U);
628   EXPECT_EQ(PlatformKind::bridgeOS, *File->getPlatforms().begin());
629   EXPECT_EQ(ArchitectureSet(AK_armv7k), File->getArchitectures());
630 
631   SmallString<4096> Buffer;
632   raw_svector_ostream OS(Buffer);
633   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
634   EXPECT_TRUE(!WriteResult);
635   EXPECT_EQ(stripWhitespace(TBDv4PlatformBridgeOS),
636             stripWhitespace(Buffer.c_str()));
637 }
638 
639 TEST(TBDv4, Target_arm_iOS) {
640   static const char TBDv4ArchArm64e[] = "--- !tapi-tbd\n"
641                                         "tbd-version: 4\n"
642                                         "targets: [  arm64e-ios ]\n"
643                                         "install-name: Test.dylib\n"
644                                         "...\n";
645 
646   auto Result =
647       TextAPIReader::get(MemoryBufferRef(TBDv4ArchArm64e, "Test.tbd"));
648   EXPECT_TRUE(!!Result);
649   auto File = std::move(Result.get());
650   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
651   EXPECT_EQ(File->getPlatforms().size(), 1U);
652   EXPECT_EQ(PlatformKind::iOS, *File->getPlatforms().begin());
653   EXPECT_EQ(ArchitectureSet(AK_arm64e), File->getArchitectures());
654 
655   SmallString<4096> Buffer;
656   raw_svector_ostream OS(Buffer);
657   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
658   EXPECT_TRUE(!WriteResult);
659   EXPECT_EQ(stripWhitespace(TBDv4ArchArm64e), stripWhitespace(Buffer.c_str()));
660 }
661 
662 TEST(TBDv4, Target_x86_macos) {
663   static const char TBDv4Targetx86MacOS[] = "--- !tapi-tbd\n"
664                                             "tbd-version: 4\n"
665                                             "targets: [  x86_64-macos ]\n"
666                                             "install-name: Test.dylib\n"
667                                             "...\n";
668 
669   auto Result =
670       TextAPIReader::get(MemoryBufferRef(TBDv4Targetx86MacOS, "Test.tbd"));
671   EXPECT_TRUE(!!Result);
672   auto File = std::move(Result.get());
673   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
674   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
675   EXPECT_EQ(File->getPlatforms().size(), 1U);
676   EXPECT_EQ(PlatformKind::macOS, *File->getPlatforms().begin());
677 
678   SmallString<4096> Buffer;
679   raw_svector_ostream OS(Buffer);
680   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
681   EXPECT_TRUE(!WriteResult);
682   EXPECT_EQ(stripWhitespace(TBDv4Targetx86MacOS),
683             stripWhitespace(Buffer.c_str()));
684 }
685 
686 TEST(TBDv4, Target_x86_ios_simulator) {
687   static const char TBDv4Targetx86iOSSim[] =
688       "--- !tapi-tbd\n"
689       "tbd-version: 4\n"
690       "targets: [  x86_64-ios-simulator  ]\n"
691       "install-name: Test.dylib\n"
692       "...\n";
693 
694   auto Result =
695       TextAPIReader::get(MemoryBufferRef(TBDv4Targetx86iOSSim, "Test.tbd"));
696   EXPECT_TRUE(!!Result);
697   auto File = std::move(Result.get());
698   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
699   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
700   EXPECT_EQ(File->getPlatforms().size(), 1U);
701   EXPECT_EQ(PlatformKind::iOSSimulator, *File->getPlatforms().begin());
702 
703   SmallString<4096> Buffer;
704   raw_svector_ostream OS(Buffer);
705   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
706   EXPECT_TRUE(!WriteResult);
707   EXPECT_EQ(stripWhitespace(TBDv4Targetx86iOSSim),
708             stripWhitespace(Buffer.c_str()));
709 }
710 
711 TEST(TBDv4, Target_x86_tvos_simulator) {
712   static const char TBDv4x86tvOSSim[] = "--- !tapi-tbd\n"
713                                         "tbd-version: 4\n"
714                                         "targets: [  x86_64-tvos-simulator  ]\n"
715                                         "install-name: Test.dylib\n"
716                                         "...\n";
717 
718   auto Result =
719       TextAPIReader::get(MemoryBufferRef(TBDv4x86tvOSSim, "Test.tbd"));
720   EXPECT_TRUE(!!Result);
721   auto File = std::move(Result.get());
722   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
723   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
724   EXPECT_EQ(File->getPlatforms().size(), 1U);
725   EXPECT_EQ(PlatformKind::tvOSSimulator, *File->getPlatforms().begin());
726 
727   SmallString<4096> Buffer;
728   raw_svector_ostream OS(Buffer);
729   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
730   EXPECT_TRUE(!WriteResult);
731   EXPECT_EQ(stripWhitespace(TBDv4x86tvOSSim), stripWhitespace(Buffer.c_str()));
732 }
733 
734 TEST(TBDv4, Target_i386_watchos_simulator) {
735   static const char TBDv4i386watchOSSim[] =
736       "--- !tapi-tbd\n"
737       "tbd-version: 4\n"
738       "targets: [  i386-watchos-simulator  ]\n"
739       "install-name: Test.dylib\n"
740       "...\n";
741 
742   auto Result =
743       TextAPIReader::get(MemoryBufferRef(TBDv4i386watchOSSim, "Test.tbd"));
744   EXPECT_TRUE(!!Result);
745   auto File = std::move(Result.get());
746   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
747   EXPECT_EQ(ArchitectureSet(AK_i386), File->getArchitectures());
748   EXPECT_EQ(File->getPlatforms().size(), 1U);
749   EXPECT_EQ(PlatformKind::watchOSSimulator, *File->getPlatforms().begin());
750 
751   SmallString<4096> Buffer;
752   raw_svector_ostream OS(Buffer);
753   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
754   EXPECT_TRUE(!WriteResult);
755   EXPECT_EQ(stripWhitespace(TBDv4i386watchOSSim),
756             stripWhitespace(Buffer.c_str()));
757 }
758 
759 TEST(TBDv4, Swift_1) {
760   static const char TBDv4SwiftVersion1[] = "--- !tapi-tbd\n"
761                                            "tbd-version: 4\n"
762                                            "targets: [  x86_64-macos ]\n"
763                                            "install-name: Test.dylib\n"
764                                            "swift-abi-version: 1\n"
765                                            "...\n";
766 
767   auto Result =
768       TextAPIReader::get(MemoryBufferRef(TBDv4SwiftVersion1, "Test.tbd"));
769   EXPECT_TRUE(!!Result);
770   auto File = std::move(Result.get());
771   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
772   EXPECT_EQ(1U, File->getSwiftABIVersion());
773 
774   // No writer test because we emit "swift-abi-version:1.0".
775 }
776 
777 TEST(TBDv4, Swift_2) {
778   static const char TBDv4Swift2[] = "--- !tapi-tbd\n"
779                                     "tbd-version: 4\n"
780                                     "targets: [  x86_64-macos ]\n"
781                                     "install-name: Test.dylib\n"
782                                     "swift-abi-version: 2\n"
783                                     "...\n";
784 
785   auto Result = TextAPIReader::get(MemoryBufferRef(TBDv4Swift2, "Test.tbd"));
786   EXPECT_TRUE(!!Result);
787   auto File = std::move(Result.get());
788   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
789   EXPECT_EQ(2U, File->getSwiftABIVersion());
790 
791   // No writer test because we emit "swift-abi-version:2.0".
792 }
793 
794 TEST(TBDv4, Swift_5) {
795   static const char TBDv4SwiftVersion5[] = "--- !tapi-tbd\n"
796                                            "tbd-version: 4\n"
797                                            "targets: [  x86_64-macos ]\n"
798                                            "install-name: Test.dylib\n"
799                                            "swift-abi-version: 5\n"
800                                            "...\n";
801 
802   auto Result =
803       TextAPIReader::get(MemoryBufferRef(TBDv4SwiftVersion5, "Test.tbd"));
804   EXPECT_TRUE(!!Result);
805   auto File = std::move(Result.get());
806   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
807   EXPECT_EQ(5U, File->getSwiftABIVersion());
808 
809   SmallString<4096> Buffer;
810   raw_svector_ostream OS(Buffer);
811   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
812   EXPECT_TRUE(!WriteResult);
813   EXPECT_EQ(stripWhitespace(TBDv4SwiftVersion5),
814             stripWhitespace(Buffer.c_str()));
815 }
816 
817 TEST(TBDv4, Swift_99) {
818   static const char TBDv4SwiftVersion99[] = "--- !tapi-tbd\n"
819                                             "tbd-version: 4\n"
820                                             "targets: [  x86_64-macos ]\n"
821                                             "install-name: Test.dylib\n"
822                                             "swift-abi-version: 99\n"
823                                             "...\n";
824 
825   auto Result =
826       TextAPIReader::get(MemoryBufferRef(TBDv4SwiftVersion99, "Test.tbd"));
827   EXPECT_TRUE(!!Result);
828   auto File = std::move(Result.get());
829   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
830   EXPECT_EQ(99U, File->getSwiftABIVersion());
831 
832   SmallString<4096> Buffer;
833   raw_svector_ostream OS(Buffer);
834   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
835   EXPECT_TRUE(!WriteResult);
836   EXPECT_EQ(stripWhitespace(TBDv4SwiftVersion99),
837             stripWhitespace(Buffer.c_str()));
838 }
839 
840 TEST(TBDv4, InvalidArchitecture) {
841   static const char TBDv4UnknownArch[] = "--- !tapi-tbd\n"
842                                          "tbd-version: 4\n"
843                                          "targets: [ foo-macos ]\n"
844                                          "install-name: Test.dylib\n"
845                                          "...\n";
846 
847   auto Result =
848       TextAPIReader::get(MemoryBufferRef(TBDv4UnknownArch, "Test.tbd"));
849   EXPECT_FALSE(!!Result);
850   auto errorMessage = toString(Result.takeError());
851   EXPECT_EQ("malformed file\nTest.tbd:3:12: error: unknown "
852             "architecture\ntargets: [ foo-macos ]\n"
853             "           ^~~~~~~~~~\n",
854             errorMessage);
855 }
856 
857 TEST(TBDv4, InvalidPlatform) {
858   static const char TBDv4FInvalidPlatform[] = "--- !tapi-tbd\n"
859                                               "tbd-version: 4\n"
860                                               "targets: [ x86_64-maos ]\n"
861                                               "install-name: Test.dylib\n"
862                                               "...\n";
863 
864   auto Result =
865       TextAPIReader::get(MemoryBufferRef(TBDv4FInvalidPlatform, "Test.tbd"));
866   EXPECT_FALSE(!!Result);
867   auto errorMessage = toString(Result.takeError());
868   EXPECT_EQ("malformed file\nTest.tbd:3:12: error: unknown platform\ntargets: "
869             "[ x86_64-maos ]\n"
870             "           ^~~~~~~~~~~~\n",
871             errorMessage);
872 }
873 
874 TEST(TBDv4, MalformedFile1) {
875   static const char TBDv4MalformedFile1[] = "--- !tapi-tbd\n"
876                                             "tbd-version: 4\n"
877                                             "...\n";
878 
879   auto Result =
880       TextAPIReader::get(MemoryBufferRef(TBDv4MalformedFile1, "Test.tbd"));
881   EXPECT_FALSE(!!Result);
882   auto errorMessage = toString(Result.takeError());
883   ASSERT_EQ("malformed file\nTest.tbd:2:1: error: missing required key "
884             "'targets'\ntbd-version: 4\n^\n",
885             errorMessage);
886 }
887 
888 TEST(TBDv4, MalformedFile2) {
889   static const char TBDv4MalformedFile2[] = "--- !tapi-tbd\n"
890                                             "tbd-version: 4\n"
891                                             "targets: [ x86_64-macos ]\n"
892                                             "install-name: Test.dylib\n"
893                                             "foobar: \"unsupported key\"\n";
894 
895   auto Result =
896       TextAPIReader::get(MemoryBufferRef(TBDv4MalformedFile2, "Test.tbd"));
897   EXPECT_FALSE(!!Result);
898   auto errorMessage = toString(Result.takeError());
899   ASSERT_EQ(
900       "malformed file\nTest.tbd:5:9: error: unknown key 'foobar'\nfoobar: "
901       "\"unsupported key\"\n        ^~~~~~~~~~~~~~~~~\n",
902       errorMessage);
903 }
904 
905 TEST(TBDv4, MalformedFile3) {
906   static const char TBDv4MalformedSwift[] = "--- !tapi-tbd\n"
907                                             "tbd-version: 4\n"
908                                             "targets: [  x86_64-macos ]\n"
909                                             "install-name: Test.dylib\n"
910                                             "swift-abi-version: 1.1\n"
911                                             "...\n";
912 
913   auto Result =
914       TextAPIReader::get(MemoryBufferRef(TBDv4MalformedSwift, "Test.tbd"));
915   EXPECT_FALSE(!!Result);
916   auto errorMessage = toString(Result.takeError());
917   EXPECT_EQ("malformed file\nTest.tbd:5:20: error: invalid Swift ABI "
918             "version.\nswift-abi-version: 1.1\n                   ^~~\n",
919             errorMessage);
920 }
921 
922 } // end namespace TBDv4
923