xref: /llvm-project/llvm/unittests/TextAPI/TextStubV4Tests.cpp (revision c6e8bfe7c9363129d98941373a94e22c226b4c08)
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 #include "llvm/TextAPI/MachO/InterfaceFile.h"
9 #include "llvm/TextAPI/MachO/TextAPIReader.h"
10 #include "llvm/TextAPI/MachO/TextAPIWriter.h"
11 #include "gtest/gtest.h"
12 #include <string>
13 #include <vector>
14 
15 using namespace llvm;
16 using namespace llvm::MachO;
17 
18 struct ExampleSymbol {
19   SymbolKind Kind;
20   std::string Name;
21   bool WeakDefined;
22   bool ThreadLocalValue;
23 };
24 using ExampleSymbolSeq = std::vector<ExampleSymbol>;
25 using UUIDs = std::vector<std::pair<Target, std::string>>;
26 
27 inline bool operator<(const ExampleSymbol &LHS, const ExampleSymbol &RHS) {
28   return std::tie(LHS.Kind, LHS.Name) < std::tie(RHS.Kind, RHS.Name);
29 }
30 
31 inline bool operator==(const ExampleSymbol &LHS, const ExampleSymbol &RHS) {
32   return std::tie(LHS.Kind, LHS.Name, LHS.WeakDefined, LHS.ThreadLocalValue) ==
33          std::tie(RHS.Kind, RHS.Name, RHS.WeakDefined, RHS.ThreadLocalValue);
34 }
35 
36 inline std::string stripWhitespace(std::string s) {
37   s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
38   return s;
39 }
40 
41 static ExampleSymbol TBDv4ExportedSymbols[] = {
42     {SymbolKind::GlobalSymbol, "_symA", false, false},
43     {SymbolKind::GlobalSymbol, "_symAB", false, false},
44     {SymbolKind::GlobalSymbol, "_symB", false, false},
45 };
46 
47 static ExampleSymbol TBDv4ReexportedSymbols[] = {
48     {SymbolKind::GlobalSymbol, "_symC", false, false},
49 };
50 
51 static ExampleSymbol TBDv4UndefinedSymbols[] = {
52     {SymbolKind::GlobalSymbol, "_symD", false, false},
53 };
54 
55 namespace TBDv4 {
56 
57 TEST(TBDv4, ReadFile) {
58   static const char tbd_v4_file[] =
59       "--- !tapi-tbd\n"
60       "tbd-version: 4\n"
61       "targets:  [ i386-macos, x86_64-macos, x86_64-ios ]\n"
62       "uuids:\n"
63       "  - target: i386-macos\n"
64       "    value: 00000000-0000-0000-0000-000000000000\n"
65       "  - target: x86_64-macos\n"
66       "    value: 11111111-1111-1111-1111-111111111111\n"
67       "  - target: x86_64-ios\n"
68       "    value: 11111111-1111-1111-1111-111111111111\n"
69       "flags: [ flat_namespace, installapi ]\n"
70       "install-name: Umbrella.framework/Umbrella\n"
71       "current-version: 1.2.3\n"
72       "compatibility-version: 1.2\n"
73       "swift-abi-version: 5\n"
74       "parent-umbrella:\n"
75       "  - targets: [ i386-macos, x86_64-macos, x86_64-ios ]\n"
76       "    umbrella: System\n"
77       "allowable-clients:\n"
78       "  - targets: [ i386-macos, x86_64-macos, x86_64-ios ]\n"
79       "    clients: [ ClientA ]\n"
80       "reexported-libraries:\n"
81       "  - targets: [ i386-macos ]\n"
82       "    libraries: [ /System/Library/Frameworks/A.framework/A ]\n"
83       "exports:\n"
84       "  - targets: [ i386-macos ]\n"
85       "    symbols: [ _symA ]\n"
86       "    objc-classes: []\n"
87       "    objc-eh-types: []\n"
88       "    objc-ivars: []\n"
89       "    weak-symbols: []\n"
90       "    thread-local-symbols: []\n"
91       "  - targets: [ x86_64-ios ]\n"
92       "    symbols: [_symB]\n"
93       "  - targets: [ x86_64-macos, x86_64-ios ]\n"
94       "    symbols: [_symAB]\n"
95       "reexports:\n"
96       "  - targets: [ i386-macos ]\n"
97       "    symbols: [_symC]\n"
98       "    objc-classes: []\n"
99       "    objc-eh-types: []\n"
100       "    objc-ivars: []\n"
101       "    weak-symbols: []\n"
102       "    thread-local-symbols: []\n"
103       "undefineds:\n"
104       "  - targets: [ i386-macos ]\n"
105       "    symbols: [ _symD ]\n"
106       "    objc-classes: []\n"
107       "    objc-eh-types: []\n"
108       "    objc-ivars: []\n"
109       "    weak-symbols: []\n"
110       "    thread-local-symbols: []\n"
111       "...\n";
112 
113   auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v4_file, "Test.tbd"));
114   EXPECT_TRUE(!!Result);
115   auto File = std::move(Result.get());
116   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
117   PlatformSet Platforms;
118   Platforms.insert(PlatformKind::macOS);
119   Platforms.insert(PlatformKind::iOS);
120   auto Archs = AK_i386 | AK_x86_64;
121   TargetList Targets = {
122       Target(AK_i386, PlatformKind::macOS),
123       Target(AK_x86_64, PlatformKind::macOS),
124       Target(AK_x86_64, PlatformKind::iOS),
125   };
126   UUIDs uuids = {{Targets[0], "00000000-0000-0000-0000-000000000000"},
127                  {Targets[1], "11111111-1111-1111-1111-111111111111"},
128                  {Targets[2], "11111111-1111-1111-1111-111111111111"}};
129   EXPECT_EQ(Archs, File->getArchitectures());
130   EXPECT_EQ(uuids, File->uuids());
131   EXPECT_EQ(Platforms.size(), File->getPlatforms().size());
132   for (auto Platform : File->getPlatforms())
133     EXPECT_EQ(Platforms.count(Platform), 1U);
134   EXPECT_EQ(std::string("Umbrella.framework/Umbrella"), File->getInstallName());
135   EXPECT_EQ(PackedVersion(1, 2, 3), File->getCurrentVersion());
136   EXPECT_EQ(PackedVersion(1, 2, 0), File->getCompatibilityVersion());
137   EXPECT_EQ(5U, File->getSwiftABIVersion());
138   EXPECT_FALSE(File->isTwoLevelNamespace());
139   EXPECT_TRUE(File->isApplicationExtensionSafe());
140   EXPECT_TRUE(File->isInstallAPI());
141   InterfaceFileRef client("ClientA", Targets);
142   InterfaceFileRef reexport("/System/Library/Frameworks/A.framework/A",
143                             {Targets[0]});
144   EXPECT_EQ(1U, File->allowableClients().size());
145   EXPECT_EQ(client, File->allowableClients().front());
146   EXPECT_EQ(1U, File->reexportedLibraries().size());
147   EXPECT_EQ(reexport, File->reexportedLibraries().front());
148 
149   ExampleSymbolSeq Exports, Reexports, Undefineds;
150   ExampleSymbol temp;
151   for (const auto *Sym : File->symbols()) {
152     temp = ExampleSymbol{Sym->getKind(), std::string(Sym->getName()),
153                          Sym->isWeakDefined(), Sym->isThreadLocalValue()};
154     EXPECT_FALSE(Sym->isWeakReferenced());
155     if (Sym->isUndefined())
156       Undefineds.emplace_back(std::move(temp));
157     else
158       Sym->isReexported() ? Reexports.emplace_back(std::move(temp))
159                           : Exports.emplace_back(std::move(temp));
160   }
161   llvm::sort(Exports.begin(), Exports.end());
162   llvm::sort(Reexports.begin(), Reexports.end());
163   llvm::sort(Undefineds.begin(), Undefineds.end());
164 
165   EXPECT_EQ(sizeof(TBDv4ExportedSymbols) / sizeof(ExampleSymbol),
166             Exports.size());
167   EXPECT_EQ(sizeof(TBDv4ReexportedSymbols) / sizeof(ExampleSymbol),
168             Reexports.size());
169   EXPECT_EQ(sizeof(TBDv4UndefinedSymbols) / sizeof(ExampleSymbol),
170             Undefineds.size());
171   EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
172                          std::begin(TBDv4ExportedSymbols)));
173   EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
174                          std::begin(TBDv4ReexportedSymbols)));
175   EXPECT_TRUE(std::equal(Undefineds.begin(), Undefineds.end(),
176                          std::begin(TBDv4UndefinedSymbols)));
177 }
178 
179 TEST(TBDv4, WriteFile) {
180   static const char tbd_v4_file[] =
181       "--- !tapi-tbd\n"
182       "tbd-version:     4\n"
183       "targets:         [ i386-macos, x86_64-ios-simulator ]\n"
184       "uuids:\n"
185       "  - target:          i386-macos\n"
186       "    value:           00000000-0000-0000-0000-000000000000\n"
187       "  - target:          x86_64-ios-simulator\n"
188       "    value:           11111111-1111-1111-1111-111111111111\n"
189       "flags:           [ installapi ]\n"
190       "install-name:    'Umbrella.framework/Umbrella'\n"
191       "current-version: 1.2.3\n"
192       "compatibility-version: 0\n"
193       "swift-abi-version: 5\n"
194       "parent-umbrella:\n"
195       "  - targets:         [ i386-macos, x86_64-ios-simulator ]\n"
196       "    umbrella:        System\n"
197       "allowable-clients:\n"
198       "  - targets:         [ i386-macos ]\n"
199       "    clients:         [ ClientA ]\n"
200       "exports:\n"
201       "  - targets:         [ i386-macos ]\n"
202       "    symbols:         [ _symA ]\n"
203       "    objc-classes:    [ Class1 ]\n"
204       "    weak-symbols:    [ _symC ]\n"
205       "  - targets:         [ x86_64-ios-simulator ]\n"
206       "    symbols:         [ _symB ]\n"
207       "...\n";
208 
209   InterfaceFile File;
210   TargetList Targets = {
211       Target(AK_i386, PlatformKind::macOS),
212       Target(AK_x86_64, PlatformKind::iOSSimulator),
213   };
214   UUIDs uuids = {{Targets[0], "00000000-0000-0000-0000-000000000000"},
215                  {Targets[1], "11111111-1111-1111-1111-111111111111"}};
216   File.setInstallName("Umbrella.framework/Umbrella");
217   File.setFileType(FileType::TBD_V4);
218   File.addTargets(Targets);
219   File.addUUID(uuids[0].first, uuids[0].second);
220   File.addUUID(uuids[1].first, uuids[1].second);
221   File.setCurrentVersion(PackedVersion(1, 2, 3));
222   File.setTwoLevelNamespace();
223   File.setInstallAPI(true);
224   File.setApplicationExtensionSafe(true);
225   File.setSwiftABIVersion(5);
226   File.addAllowableClient("ClientA", Targets[0]);
227   File.addParentUmbrella(Targets[0], "System");
228   File.addParentUmbrella(Targets[1], "System");
229   File.addSymbol(SymbolKind::GlobalSymbol, "_symA", {Targets[0]});
230   File.addSymbol(SymbolKind::GlobalSymbol, "_symB", {Targets[1]});
231   File.addSymbol(SymbolKind::GlobalSymbol, "_symC", {Targets[0]},
232                  SymbolFlags::WeakDefined);
233   File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", {Targets[0]});
234 
235   SmallString<4096> Buffer;
236   raw_svector_ostream OS(Buffer);
237   auto Result = TextAPIWriter::writeToStream(OS, File);
238   EXPECT_FALSE(Result);
239   EXPECT_STREQ(tbd_v4_file, Buffer.c_str());
240 }
241 
242 TEST(TBDv4, MultipleTargets) {
243   static const char tbd_multiple_targets[] =
244       "--- !tapi-tbd\n"
245       "tbd-version: 4\n"
246       "targets: [ i386-maccatalyst, x86_64-tvos, arm64-ios ]\n"
247       "install-name: Test.dylib\n"
248       "...\n";
249 
250   auto Result =
251       TextAPIReader::get(MemoryBufferRef(tbd_multiple_targets, "Test.tbd"));
252   EXPECT_TRUE(!!Result);
253   PlatformSet Platforms;
254   Platforms.insert(PlatformKind::macCatalyst);
255   Platforms.insert(PlatformKind::tvOS);
256   Platforms.insert(PlatformKind::iOS);
257   auto File = std::move(Result.get());
258   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
259   EXPECT_EQ(AK_x86_64 | AK_arm64 | AK_i386, File->getArchitectures());
260   EXPECT_EQ(Platforms.size(), File->getPlatforms().size());
261   for (auto Platform : File->getPlatforms())
262     EXPECT_EQ(Platforms.count(Platform), 1U);
263 
264   SmallString<4096> Buffer;
265   raw_svector_ostream OS(Buffer);
266   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
267   EXPECT_TRUE(!WriteResult);
268   EXPECT_EQ(stripWhitespace(tbd_multiple_targets),
269             stripWhitespace(Buffer.c_str()));
270 }
271 
272 TEST(TBDv4, MultipleTargetsSameArch) {
273   static const char tbd_targets_same_arch[] =
274       "--- !tapi-tbd\n"
275       "tbd-version: 4\n"
276       "targets: [ x86_64-tvos , x86_64-maccatalyst ]\n"
277       "install-name: Test.dylib\n"
278       "...\n";
279 
280   auto Result =
281       TextAPIReader::get(MemoryBufferRef(tbd_targets_same_arch, "Test.tbd"));
282   EXPECT_TRUE(!!Result);
283   PlatformSet Platforms;
284   Platforms.insert(PlatformKind::tvOS);
285   Platforms.insert(PlatformKind::macCatalyst);
286   auto File = std::move(Result.get());
287   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
288   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
289   EXPECT_EQ(Platforms.size(), File->getPlatforms().size());
290   for (auto Platform : File->getPlatforms())
291     EXPECT_EQ(Platforms.count(Platform), 1U);
292 
293   SmallString<4096> Buffer;
294   raw_svector_ostream OS(Buffer);
295   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
296   EXPECT_TRUE(!WriteResult);
297   EXPECT_EQ(stripWhitespace(tbd_targets_same_arch),
298             stripWhitespace(Buffer.c_str()));
299 }
300 
301 TEST(TBDv4, MultipleTargetsSamePlatform) {
302   static const char tbd_multiple_targets_same_platform[] =
303       "--- !tapi-tbd\n"
304       "tbd-version: 4\n"
305       "targets: [ armv7k-ios , arm64-ios]\n"
306       "install-name: Test.dylib\n"
307       "...\n";
308 
309   auto Result = TextAPIReader::get(
310       MemoryBufferRef(tbd_multiple_targets_same_platform, "Test.tbd"));
311   EXPECT_TRUE(!!Result);
312   auto File = std::move(Result.get());
313   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
314   EXPECT_EQ(AK_arm64 | AK_armv7k, File->getArchitectures());
315   EXPECT_EQ(File->getPlatforms().size(), 1U);
316   EXPECT_EQ(PlatformKind::iOS, *File->getPlatforms().begin());
317 
318   SmallString<4096> Buffer;
319   raw_svector_ostream OS(Buffer);
320   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
321   EXPECT_TRUE(!WriteResult);
322   EXPECT_EQ(stripWhitespace(tbd_multiple_targets_same_platform),
323             stripWhitespace(Buffer.c_str()));
324 }
325 
326 TEST(TBDv4, Target_maccatalyst) {
327   static const char tbd_target_maccatalyst[] =
328       "--- !tapi-tbd\n"
329       "tbd-version: 4\n"
330       "targets: [  x86_64-maccatalyst ]\n"
331       "install-name: Test.dylib\n"
332       "...\n";
333 
334   auto Result =
335       TextAPIReader::get(MemoryBufferRef(tbd_target_maccatalyst, "Test.tbd"));
336   EXPECT_TRUE(!!Result);
337   auto File = std::move(Result.get());
338   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
339   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
340   EXPECT_EQ(File->getPlatforms().size(), 1U);
341   EXPECT_EQ(PlatformKind::macCatalyst, *File->getPlatforms().begin());
342 
343   SmallString<4096> Buffer;
344   raw_svector_ostream OS(Buffer);
345   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
346   EXPECT_TRUE(!WriteResult);
347   EXPECT_EQ(stripWhitespace(tbd_target_maccatalyst),
348             stripWhitespace(Buffer.c_str()));
349 }
350 
351 TEST(TBDv4, Target_x86_ios) {
352   static const char tbd_target_x86_ios[] = "--- !tapi-tbd\n"
353                                            "tbd-version: 4\n"
354                                            "targets: [  x86_64-ios ]\n"
355                                            "install-name: Test.dylib\n"
356                                            "...\n";
357 
358   auto Result =
359       TextAPIReader::get(MemoryBufferRef(tbd_target_x86_ios, "Test.tbd"));
360   EXPECT_TRUE(!!Result);
361   auto File = std::move(Result.get());
362   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
363   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
364   EXPECT_EQ(File->getPlatforms().size(), 1U);
365   EXPECT_EQ(PlatformKind::iOS, *File->getPlatforms().begin());
366 
367   SmallString<4096> Buffer;
368   raw_svector_ostream OS(Buffer);
369   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
370   EXPECT_TRUE(!WriteResult);
371   EXPECT_EQ(stripWhitespace(tbd_target_x86_ios),
372             stripWhitespace(Buffer.c_str()));
373 }
374 
375 TEST(TBDv4, Target_arm_bridgeOS) {
376   static const char tbd_platform_bridgeos[] = "--- !tapi-tbd\n"
377                                               "tbd-version: 4\n"
378                                               "targets: [  armv7k-bridgeos ]\n"
379                                               "install-name: Test.dylib\n"
380                                               "...\n";
381 
382   auto Result =
383       TextAPIReader::get(MemoryBufferRef(tbd_platform_bridgeos, "Test.tbd"));
384   EXPECT_TRUE(!!Result);
385   auto File = std::move(Result.get());
386   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
387   EXPECT_EQ(File->getPlatforms().size(), 1U);
388   EXPECT_EQ(PlatformKind::bridgeOS, *File->getPlatforms().begin());
389   EXPECT_EQ(ArchitectureSet(AK_armv7k), File->getArchitectures());
390 
391   SmallString<4096> Buffer;
392   raw_svector_ostream OS(Buffer);
393   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
394   EXPECT_TRUE(!WriteResult);
395   EXPECT_EQ(stripWhitespace(tbd_platform_bridgeos),
396             stripWhitespace(Buffer.c_str()));
397 }
398 
399 TEST(TBDv4, Target_x86_macos) {
400   static const char tbd_x86_macos[] = "--- !tapi-tbd\n"
401                                       "tbd-version: 4\n"
402                                       "targets: [  x86_64-macos ]\n"
403                                       "install-name: Test.dylib\n"
404                                       "...\n";
405 
406   auto Result = TextAPIReader::get(MemoryBufferRef(tbd_x86_macos, "Test.tbd"));
407   EXPECT_TRUE(!!Result);
408   auto File = std::move(Result.get());
409   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
410   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
411   EXPECT_EQ(File->getPlatforms().size(), 1U);
412   EXPECT_EQ(PlatformKind::macOS, *File->getPlatforms().begin());
413 
414   SmallString<4096> Buffer;
415   raw_svector_ostream OS(Buffer);
416   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
417   EXPECT_TRUE(!WriteResult);
418   EXPECT_EQ(stripWhitespace(tbd_x86_macos), stripWhitespace(Buffer.c_str()));
419 }
420 
421 TEST(TBDv4, Target_x86_ios_simulator) {
422   static const char tbd_x86_ios_sim[] = "--- !tapi-tbd\n"
423                                         "tbd-version: 4\n"
424                                         "targets: [  x86_64-ios-simulator  ]\n"
425                                         "install-name: Test.dylib\n"
426                                         "...\n";
427 
428   auto Result =
429       TextAPIReader::get(MemoryBufferRef(tbd_x86_ios_sim, "Test.tbd"));
430   EXPECT_TRUE(!!Result);
431   auto File = std::move(Result.get());
432   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
433   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
434   EXPECT_EQ(File->getPlatforms().size(), 1U);
435   EXPECT_EQ(PlatformKind::iOSSimulator, *File->getPlatforms().begin());
436 
437   SmallString<4096> Buffer;
438   raw_svector_ostream OS(Buffer);
439   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
440   EXPECT_TRUE(!WriteResult);
441   EXPECT_EQ(stripWhitespace(tbd_x86_ios_sim), stripWhitespace(Buffer.c_str()));
442 }
443 
444 TEST(TBDv4, Target_x86_tvos_simulator) {
445   static const char tbd_x86_tvos_sim[] =
446       "--- !tapi-tbd\n"
447       "tbd-version: 4\n"
448       "targets: [  x86_64-tvos-simulator  ]\n"
449       "install-name: Test.dylib\n"
450       "...\n";
451 
452   auto Result =
453       TextAPIReader::get(MemoryBufferRef(tbd_x86_tvos_sim, "Test.tbd"));
454   EXPECT_TRUE(!!Result);
455   auto File = std::move(Result.get());
456   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
457   EXPECT_EQ(ArchitectureSet(AK_x86_64), File->getArchitectures());
458   EXPECT_EQ(File->getPlatforms().size(), 1U);
459   EXPECT_EQ(PlatformKind::tvOSSimulator, *File->getPlatforms().begin());
460 
461   SmallString<4096> Buffer;
462   raw_svector_ostream OS(Buffer);
463   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
464   EXPECT_TRUE(!WriteResult);
465   EXPECT_EQ(stripWhitespace(tbd_x86_tvos_sim), stripWhitespace(Buffer.c_str()));
466 }
467 
468 TEST(TBDv4, Target_i386_watchos_simulator) {
469   static const char tbd_i386_watchos_sim[] =
470       "--- !tapi-tbd\n"
471       "tbd-version: 4\n"
472       "targets: [  i386-watchos-simulator  ]\n"
473       "install-name: Test.dylib\n"
474       "...\n";
475 
476   auto Result =
477       TextAPIReader::get(MemoryBufferRef(tbd_i386_watchos_sim, "Test.tbd"));
478   EXPECT_TRUE(!!Result);
479   auto File = std::move(Result.get());
480   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
481   EXPECT_EQ(ArchitectureSet(AK_i386), File->getArchitectures());
482   EXPECT_EQ(File->getPlatforms().size(), 1U);
483   EXPECT_EQ(PlatformKind::watchOSSimulator, *File->getPlatforms().begin());
484 
485   SmallString<4096> Buffer;
486   raw_svector_ostream OS(Buffer);
487   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
488   EXPECT_TRUE(!WriteResult);
489   EXPECT_EQ(stripWhitespace(tbd_i386_watchos_sim),
490             stripWhitespace(Buffer.c_str()));
491 }
492 
493 TEST(TBDv4, Swift_1) {
494   static const char tbd_swift_1[] = "--- !tapi-tbd\n"
495                                     "tbd-version: 4\n"
496                                     "targets: [  x86_64-macos ]\n"
497                                     "install-name: Test.dylib\n"
498                                     "swift-abi-version: 1\n"
499                                     "...\n";
500 
501   auto Result = TextAPIReader::get(MemoryBufferRef(tbd_swift_1, "Test.tbd"));
502   EXPECT_TRUE(!!Result);
503   auto File = std::move(Result.get());
504   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
505   EXPECT_EQ(1U, File->getSwiftABIVersion());
506 
507   // No writer test because we emit "swift-abi-version:1.0".
508 }
509 
510 TEST(TBDv4, Swift_2) {
511   static const char tbd_v4_swift_2[] = "--- !tapi-tbd\n"
512                                        "tbd-version: 4\n"
513                                        "targets: [  x86_64-macos ]\n"
514                                        "install-name: Test.dylib\n"
515                                        "swift-abi-version: 2\n"
516                                        "...\n";
517 
518   auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v4_swift_2, "Test.tbd"));
519   EXPECT_TRUE(!!Result);
520   auto File = std::move(Result.get());
521   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
522   EXPECT_EQ(2U, File->getSwiftABIVersion());
523 
524   // No writer test because we emit "swift-abi-version:2.0".
525 }
526 
527 TEST(TBDv4, Swift_5) {
528   static const char tbd_swift_5[] = "--- !tapi-tbd\n"
529                                     "tbd-version: 4\n"
530                                     "targets: [  x86_64-macos ]\n"
531                                     "install-name: Test.dylib\n"
532                                     "swift-abi-version: 5\n"
533                                     "...\n";
534 
535   auto Result = TextAPIReader::get(MemoryBufferRef(tbd_swift_5, "Test.tbd"));
536   EXPECT_TRUE(!!Result);
537   auto File = std::move(Result.get());
538   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
539   EXPECT_EQ(5U, File->getSwiftABIVersion());
540 
541   SmallString<4096> Buffer;
542   raw_svector_ostream OS(Buffer);
543   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
544   EXPECT_TRUE(!WriteResult);
545   EXPECT_EQ(stripWhitespace(tbd_swift_5), stripWhitespace(Buffer.c_str()));
546 }
547 
548 TEST(TBDv4, Swift_99) {
549   static const char tbd_swift_99[] = "--- !tapi-tbd\n"
550                                      "tbd-version: 4\n"
551                                      "targets: [  x86_64-macos ]\n"
552                                      "install-name: Test.dylib\n"
553                                      "swift-abi-version: 99\n"
554                                      "...\n";
555 
556   auto Result = TextAPIReader::get(MemoryBufferRef(tbd_swift_99, "Test.tbd"));
557   EXPECT_TRUE(!!Result);
558   auto File = std::move(Result.get());
559   EXPECT_EQ(FileType::TBD_V4, File->getFileType());
560   EXPECT_EQ(99U, File->getSwiftABIVersion());
561 
562   SmallString<4096> Buffer;
563   raw_svector_ostream OS(Buffer);
564   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
565   EXPECT_TRUE(!WriteResult);
566   EXPECT_EQ(stripWhitespace(tbd_swift_99), stripWhitespace(Buffer.c_str()));
567 }
568 
569 TEST(TBDv4, InvalidArchitecture) {
570   static const char tbd_file_unknown_architecture[] =
571       "--- !tapi-tbd\n"
572       "tbd-version: 4\n"
573       "targets: [ foo-macos ]\n"
574       "install-name: Test.dylib\n"
575       "...\n";
576 
577   auto Result = TextAPIReader::get(
578       MemoryBufferRef(tbd_file_unknown_architecture, "Test.tbd"));
579   EXPECT_FALSE(!!Result);
580   auto errorMessage = toString(Result.takeError());
581   EXPECT_EQ("malformed file\nTest.tbd:3:12: error: unknown "
582             "architecture\ntargets: [ foo-macos ]\n"
583             "           ^~~~~~~~~~\n",
584             errorMessage);
585 }
586 
587 TEST(TBDv4, InvalidPlatform) {
588   static const char tbd_file_invalid_platform[] = "--- !tapi-tbd\n"
589                                                   "tbd-version: 4\n"
590                                                   "targets: [ x86_64-maos ]\n"
591                                                   "install-name: Test.dylib\n"
592                                                   "...\n";
593 
594   auto Result = TextAPIReader::get(
595       MemoryBufferRef(tbd_file_invalid_platform, "Test.tbd"));
596   EXPECT_FALSE(!!Result);
597   auto errorMessage = toString(Result.takeError());
598   EXPECT_EQ("malformed file\nTest.tbd:3:12: error: unknown platform\ntargets: "
599             "[ x86_64-maos ]\n"
600             "           ^~~~~~~~~~~~\n",
601             errorMessage);
602 }
603 
604 TEST(TBDv4, MalformedFile1) {
605   static const char malformed_file1[] = "--- !tapi-tbd\n"
606                                         "tbd-version: 4\n"
607                                         "...\n";
608 
609   auto Result =
610       TextAPIReader::get(MemoryBufferRef(malformed_file1, "Test.tbd"));
611   EXPECT_FALSE(!!Result);
612   auto errorMessage = toString(Result.takeError());
613   ASSERT_EQ("malformed file\nTest.tbd:2:1: error: missing required key "
614             "'targets'\ntbd-version: 4\n^\n",
615             errorMessage);
616 }
617 
618 TEST(TBDv4, MalformedFile2) {
619   static const char malformed_file2[] = "--- !tapi-tbd\n"
620                                         "tbd-version: 4\n"
621                                         "targets: [ x86_64-macos ]\n"
622                                         "install-name: Test.dylib\n"
623                                         "foobar: \"unsupported key\"\n";
624 
625   auto Result =
626       TextAPIReader::get(MemoryBufferRef(malformed_file2, "Test.tbd"));
627   EXPECT_FALSE(!!Result);
628   auto errorMessage = toString(Result.takeError());
629   ASSERT_EQ(
630       "malformed file\nTest.tbd:5:9: error: unknown key 'foobar'\nfoobar: "
631       "\"unsupported key\"\n        ^~~~~~~~~~~~~~~~~\n",
632       errorMessage);
633 }
634 
635 TEST(TBDv4, MalformedFile3) {
636   static const char tbd_v4_swift_1_1[] = "--- !tapi-tbd\n"
637                                          "tbd-version: 4\n"
638                                          "targets: [  x86_64-macos ]\n"
639                                          "install-name: Test.dylib\n"
640                                          "swift-abi-version: 1.1\n"
641                                          "...\n";
642 
643   auto Result =
644       TextAPIReader::get(MemoryBufferRef(tbd_v4_swift_1_1, "Test.tbd"));
645   EXPECT_FALSE(!!Result);
646   auto errorMessage = toString(Result.takeError());
647   EXPECT_EQ("malformed file\nTest.tbd:5:20: error: invalid Swift ABI "
648             "version.\nswift-abi-version: 1.1\n                   ^~~\n",
649             errorMessage);
650 }
651 
652 } // end namespace TBDv4
653