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 
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 struct ExportedSymbol {
20   SymbolKind Kind;
21   std::string Name;
22   bool WeakDefined;
23   bool ThreadLocalValue;
24 };
25 using ExportedSymbolSeq = std::vector<ExportedSymbol>;
26 using UUIDs = std::vector<std::pair<Target, std::string>>;
27 
28 inline bool operator<(const ExportedSymbol &lhs, const ExportedSymbol &rhs) {
29   return std::tie(lhs.Kind, lhs.Name) < std::tie(rhs.Kind, rhs.Name);
30 }
31 
32 inline bool operator==(const ExportedSymbol &lhs, const ExportedSymbol &rhs) {
33   return std::tie(lhs.Kind, lhs.Name, lhs.WeakDefined, lhs.ThreadLocalValue) ==
34          std::tie(rhs.Kind, rhs.Name, rhs.WeakDefined, rhs.ThreadLocalValue);
35 }
36 
37 inline std::string stripWhitespace(std::string s) {
38   s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
39   return s;
40 }
41 
42 static ExportedSymbol TBDv3Symbols[] = {
43     {SymbolKind::GlobalSymbol, "$ld$hide$os9.0$_sym1", false, false},
44     {SymbolKind::GlobalSymbol, "_sym1", false, false},
45     {SymbolKind::GlobalSymbol, "_sym2", false, false},
46     {SymbolKind::GlobalSymbol, "_sym3", false, false},
47     {SymbolKind::GlobalSymbol, "_sym4", false, false},
48     {SymbolKind::GlobalSymbol, "_sym5", false, false},
49     {SymbolKind::GlobalSymbol, "_tlv1", false, true},
50     {SymbolKind::GlobalSymbol, "_tlv3", false, true},
51     {SymbolKind::GlobalSymbol, "_weak1", true, false},
52     {SymbolKind::GlobalSymbol, "_weak2", true, false},
53     {SymbolKind::GlobalSymbol, "_weak3", true, false},
54     {SymbolKind::ObjectiveCClass, "class1", false, false},
55     {SymbolKind::ObjectiveCClass, "class2", false, false},
56     {SymbolKind::ObjectiveCClass, "class3", false, false},
57     {SymbolKind::ObjectiveCClassEHType, "class1", false, false},
58     {SymbolKind::ObjectiveCInstanceVariable, "class1._ivar1", false, false},
59     {SymbolKind::ObjectiveCInstanceVariable, "class1._ivar2", false, false},
60     {SymbolKind::ObjectiveCInstanceVariable, "class1._ivar3", false, false},
61 };
62 
63 namespace TBDv3 {
64 
65 TEST(TBDv3, ReadFile) {
66   static const char tbd_v3_file1[] =
67       "--- !tapi-tbd-v3\n"
68       "archs: [ armv7, arm64 ]\n"
69       "uuids: [ 'armv7: 00000000-0000-0000-0000-000000000000',\n"
70       "         'arm64: 11111111-1111-1111-1111-111111111111']\n"
71       "platform: ios\n"
72       "flags: [ installapi ]\n"
73       "install-name: Test.dylib\n"
74       "current-version: 2.3.4\n"
75       "compatibility-version: 1.0\n"
76       "swift-abi-version: 1.1\n"
77       "parent-umbrella: Umbrella.dylib\n"
78       "exports:\n"
79       "  - archs: [ armv7, arm64 ]\n"
80       "    allowable-clients: [ clientA ]\n"
81       "    re-exports: [ /usr/lib/libfoo.dylib ]\n"
82       "    symbols: [ _sym1, _sym2, _sym3, _sym4, $ld$hide$os9.0$_sym1 ]\n"
83       "    objc-classes: [ class1, class2 ]\n"
84       "    objc-eh-types: [ class1 ]\n"
85       "    objc-ivars: [ class1._ivar1, class1._ivar2 ]\n"
86       "    weak-def-symbols: [ _weak1, _weak2 ]\n"
87       "    thread-local-symbols: [ _tlv1, _tlv3 ]\n"
88       "  - archs: [ armv7 ]\n"
89       "    symbols: [ _sym5 ]\n"
90       "    objc-classes: [ class3 ]\n"
91       "    objc-ivars: [ class1._ivar3 ]\n"
92       "    weak-def-symbols: [ _weak3 ]\n"
93       "    thread-local-symbols: [ _tlv3 ]\n"
94       "...\n";
95 
96   auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v3_file1, "Test.tbd"));
97   EXPECT_TRUE(!!Result);
98   auto File = std::move(Result.get());
99   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
100   auto Archs = AK_armv7 | AK_arm64;
101   auto Platform = PlatformKind::iOS;
102   TargetList Targets;
103   for (auto &&arch : Archs)
104     Targets.emplace_back(Target(arch, Platform));
105   EXPECT_EQ(Archs, File->getArchitectures());
106   UUIDs Uuids = {{Target(AK_armv7, PlatformKind::unknown),
107                   "00000000-0000-0000-0000-000000000000"},
108                  {Target(AK_arm64, PlatformKind::unknown),
109                   "11111111-1111-1111-1111-111111111111"}};
110   EXPECT_EQ(Uuids, File->uuids());
111   EXPECT_EQ(File->getPlatforms().size(), 1U);
112   EXPECT_EQ(Platform, *File->getPlatforms().begin());
113   EXPECT_EQ(std::string("Test.dylib"), File->getInstallName());
114   EXPECT_EQ(PackedVersion(2, 3, 4), File->getCurrentVersion());
115   EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());
116   EXPECT_EQ(2U, File->getSwiftABIVersion());
117   EXPECT_EQ(ObjCConstraintType::Retain_Release, File->getObjCConstraint());
118   EXPECT_TRUE(File->isTwoLevelNamespace());
119   EXPECT_TRUE(File->isApplicationExtensionSafe());
120   EXPECT_TRUE(File->isInstallAPI());
121   InterfaceFileRef client("clientA", Targets);
122   InterfaceFileRef reexport("/usr/lib/libfoo.dylib", Targets);
123   EXPECT_EQ(1U, File->allowableClients().size());
124   EXPECT_EQ(client, File->allowableClients().front());
125   EXPECT_EQ(1U, File->reexportedLibraries().size());
126   EXPECT_EQ(reexport, File->reexportedLibraries().front());
127 
128   ExportedSymbolSeq Exports;
129   for (const auto *Sym : File->symbols()) {
130     EXPECT_FALSE(Sym->isWeakReferenced());
131     EXPECT_FALSE(Sym->isUndefined());
132     Exports.emplace_back(
133         ExportedSymbol{Sym->getKind(), std::string(Sym->getName()),
134                        Sym->isWeakDefined(), Sym->isThreadLocalValue()});
135   }
136   llvm::sort(Exports.begin(), Exports.end());
137 
138   EXPECT_EQ(sizeof(TBDv3Symbols) / sizeof(ExportedSymbol), Exports.size());
139   EXPECT_TRUE(
140       std::equal(Exports.begin(), Exports.end(), std::begin(TBDv3Symbols)));
141 }
142 
143 TEST(TBDv3, WriteFile) {
144   static const char tbd_v3_file3[] =
145       "--- !tapi-tbd-v3\n"
146       "archs:           [ i386, x86_64 ]\n"
147       "platform:        macosx\n"
148       "install-name:    '/usr/lib/libfoo.dylib'\n"
149       "current-version: 1.2.3\n"
150       "compatibility-version: 0\n"
151       "swift-abi-version: 5\n"
152       "exports:\n"
153       "  - archs:           [ i386 ]\n"
154       "    symbols:         [ _sym1 ]\n"
155       "    weak-def-symbols: [ _sym2 ]\n"
156       "    thread-local-symbols: [ _sym3 ]\n"
157       "  - archs:           [ x86_64 ]\n"
158       "    allowable-clients: [ clientA ]\n"
159       "    re-exports:      [ '/usr/lib/libfoo.dylib' ]\n"
160       "    objc-classes:    [ Class1 ]\n"
161       "    objc-eh-types:   [ Class1 ]\n"
162       "    objc-ivars:      [ Class1._ivar1 ]\n"
163       "...\n";
164 
165   InterfaceFile File;
166   TargetList Targets;
167   for (auto &&arch : AK_i386 | AK_x86_64)
168     Targets.emplace_back(Target(arch, PlatformKind::macOS));
169   File.setPath("libfoo.dylib");
170   File.setInstallName("/usr/lib/libfoo.dylib");
171   File.setFileType(FileType::TBD_V3);
172   File.addTargets(Targets);
173   File.setCurrentVersion(PackedVersion(1, 2, 3));
174   File.setTwoLevelNamespace();
175   File.setApplicationExtensionSafe();
176   File.setSwiftABIVersion(5);
177   File.setObjCConstraint(ObjCConstraintType::Retain_Release);
178   File.addAllowableClient("clientA", Targets[1]);
179   File.addReexportedLibrary("/usr/lib/libfoo.dylib", Targets[1]);
180   File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", {Targets[0]});
181   File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", {Targets[0]},
182                  SymbolFlags::WeakDefined);
183   File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", {Targets[0]},
184                  SymbolFlags::ThreadLocalValue);
185   File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", {Targets[1]});
186   File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", {Targets[1]});
187   File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1",
188                  {Targets[1]});
189 
190   SmallString<4096> Buffer;
191   raw_svector_ostream OS(Buffer);
192   auto Result = TextAPIWriter::writeToStream(OS, File);
193   EXPECT_FALSE(Result);
194   EXPECT_STREQ(tbd_v3_file3, Buffer.c_str());
195 }
196 
197 TEST(TBDv3, Platform_macOS) {
198   static const char tbd_v3_platform_macos[] = "--- !tapi-tbd-v3\n"
199                                               "archs: [ x86_64 ]\n"
200                                               "platform: macosx\n"
201                                               "install-name: Test.dylib\n"
202                                               "...\n";
203 
204   auto Result =
205       TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_macos, "Test.tbd"));
206   EXPECT_TRUE(!!Result);
207   auto Platform = PlatformKind::macOS;
208   auto File = std::move(Result.get());
209   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
210   EXPECT_EQ(File->getPlatforms().size(), 1U);
211   EXPECT_EQ(Platform, *File->getPlatforms().begin());
212 
213   SmallString<4096> Buffer;
214   raw_svector_ostream OS(Buffer);
215   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
216   EXPECT_TRUE(!WriteResult);
217   EXPECT_EQ(stripWhitespace(tbd_v3_platform_macos),
218             stripWhitespace(Buffer.c_str()));
219 }
220 
221 TEST(TBDv3, Platform_iOS) {
222   static const char tbd_v3_platform_ios[] = "--- !tapi-tbd-v3\n"
223                                             "archs: [ arm64 ]\n"
224                                             "platform: ios\n"
225                                             "install-name: Test.dylib\n"
226                                             "...\n";
227 
228   auto Result =
229       TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_ios, "Test.tbd"));
230   EXPECT_TRUE(!!Result);
231   auto Platform = PlatformKind::iOS;
232   auto File = std::move(Result.get());
233   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
234   EXPECT_EQ(File->getPlatforms().size(), 1U);
235   EXPECT_EQ(Platform, *File->getPlatforms().begin());
236 
237   SmallString<4096> Buffer;
238   raw_svector_ostream OS(Buffer);
239   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
240   EXPECT_TRUE(!WriteResult);
241   EXPECT_EQ(stripWhitespace(tbd_v3_platform_ios),
242             stripWhitespace(Buffer.c_str()));
243 }
244 
245 TEST(TBDv3, Platform_watchOS) {
246   static const char tbd_v3_platform_watchos[] = "--- !tapi-tbd-v3\n"
247                                                 "archs: [ armv7k ]\n"
248                                                 "platform: watchos\n"
249                                                 "install-name: Test.dylib\n"
250                                                 "...\n";
251 
252   auto Result =
253       TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_watchos, "Test.tbd"));
254   EXPECT_TRUE(!!Result);
255   auto Platform = PlatformKind::watchOS;
256   auto File = std::move(Result.get());
257   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
258   EXPECT_EQ(File->getPlatforms().size(), 1U);
259   EXPECT_EQ(Platform, *File->getPlatforms().begin());
260 
261   SmallString<4096> Buffer;
262   raw_svector_ostream OS(Buffer);
263   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
264   EXPECT_TRUE(!WriteResult);
265   EXPECT_EQ(stripWhitespace(tbd_v3_platform_watchos),
266             stripWhitespace(Buffer.c_str()));
267 }
268 
269 TEST(TBDv3, Platform_tvOS) {
270   static const char tbd_v3_platform_tvos[] = "--- !tapi-tbd-v3\n"
271                                              "archs: [ arm64 ]\n"
272                                              "platform: tvos\n"
273                                              "install-name: Test.dylib\n"
274                                              "...\n";
275 
276   auto Result =
277       TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_tvos, "Test.tbd"));
278   EXPECT_TRUE(!!Result);
279   auto File = std::move(Result.get());
280   auto Platform = PlatformKind::tvOS;
281   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
282   EXPECT_EQ(File->getPlatforms().size(), 1U);
283   EXPECT_EQ(Platform, *File->getPlatforms().begin());
284 
285   SmallString<4096> Buffer;
286   raw_svector_ostream OS(Buffer);
287   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
288   EXPECT_TRUE(!WriteResult);
289   EXPECT_EQ(stripWhitespace(tbd_v3_platform_tvos),
290             stripWhitespace(Buffer.c_str()));
291 }
292 
293 TEST(TBDv3, Platform_bridgeOS) {
294   static const char tbd_v3_platform_bridgeos[] = "--- !tapi-tbd-v3\n"
295                                                  "archs: [ armv7k ]\n"
296                                                  "platform: bridgeos\n"
297                                                  "install-name: Test.dylib\n"
298                                                  "...\n";
299 
300   auto Result =
301       TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_bridgeos, "Test.tbd"));
302   EXPECT_TRUE(!!Result);
303   auto Platform = PlatformKind::bridgeOS;
304   auto File = std::move(Result.get());
305   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
306   EXPECT_EQ(File->getPlatforms().size(), 1U);
307   EXPECT_EQ(Platform, *File->getPlatforms().begin());
308 
309   SmallString<4096> Buffer;
310   raw_svector_ostream OS(Buffer);
311   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
312   EXPECT_TRUE(!WriteResult);
313   EXPECT_EQ(stripWhitespace(tbd_v3_platform_bridgeos),
314             stripWhitespace(Buffer.c_str()));
315 }
316 
317 TEST(TBDv3, Platform_macCatalyst) {
318   static const char tbd_v3_platform_iosmac[] = "--- !tapi-tbd-v3\n"
319                                                  "archs: [ armv7k ]\n"
320                                                  "platform: iosmac\n"
321                                                  "install-name: Test.dylib\n"
322                                                  "...\n";
323 
324   auto Result =
325       TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_iosmac, "Test.tbd"));
326   EXPECT_TRUE(!!Result);
327   auto Platform = PlatformKind::macCatalyst;
328   auto File = std::move(Result.get());
329   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
330   EXPECT_EQ(Platform, *File->getPlatforms().begin());
331 
332   SmallString<4096> Buffer;
333   raw_svector_ostream OS(Buffer);
334   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
335   EXPECT_TRUE(!WriteResult);
336   EXPECT_EQ(stripWhitespace(tbd_v3_platform_iosmac), stripWhitespace(Buffer.c_str()));
337 }
338 
339 TEST(TBDv3, Platform_zippered) {
340   static const char tbd_v3_platform_zip[] = "--- !tapi-tbd-v3\n"
341                                                  "archs: [ armv7k ]\n"
342                                                  "platform: zippered\n"
343                                                  "install-name: Test.dylib\n"
344                                                  "...\n";
345 
346   auto Result =
347       TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_zip, "Test.tbd"));
348   EXPECT_TRUE(!!Result);
349   auto File = std::move(Result.get());
350   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
351 
352   PlatformSet Platforms;
353   Platforms.insert(PlatformKind::macOS);
354   Platforms.insert(PlatformKind::macCatalyst);
355   EXPECT_EQ(Platforms.size(), File->getPlatforms().size());
356   for (auto Platform : File->getPlatforms())
357 	    EXPECT_EQ(Platforms.count(Platform), 1U);
358 
359   SmallString<4096> Buffer;
360   raw_svector_ostream OS(Buffer);
361   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
362   EXPECT_TRUE(!WriteResult);
363   EXPECT_EQ(stripWhitespace(tbd_v3_platform_zip),
364             stripWhitespace(Buffer.c_str()));
365 }
366 
367 TEST(TBDv3, Swift_1_0) {
368   static const char tbd_v3_swift_1_0[] = "--- !tapi-tbd-v3\n"
369                                          "archs: [ arm64 ]\n"
370                                          "platform: ios\n"
371                                          "install-name: Test.dylib\n"
372                                          "swift-abi-version: 1.0\n"
373                                          "...\n";
374 
375   auto Result =
376       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_1_0, "Test.tbd"));
377   EXPECT_TRUE(!!Result);
378   auto File = std::move(Result.get());
379   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
380   EXPECT_EQ(1U, File->getSwiftABIVersion());
381 
382   SmallString<4096> Buffer;
383   raw_svector_ostream OS(Buffer);
384   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
385   EXPECT_TRUE(!WriteResult);
386   EXPECT_EQ(stripWhitespace(tbd_v3_swift_1_0), stripWhitespace(Buffer.c_str()));
387 }
388 
389 TEST(TBDv3, Swift_1_1) {
390   static const char tbd_v3_swift_1_1[] = "--- !tapi-tbd-v3\n"
391                                          "archs: [ arm64 ]\n"
392                                          "platform: ios\n"
393                                          "install-name: Test.dylib\n"
394                                          "swift-abi-version: 1.1\n"
395                                          "...\n";
396 
397   auto Result =
398       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_1_1, "Test.tbd"));
399   EXPECT_TRUE(!!Result);
400   auto File = std::move(Result.get());
401   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
402   EXPECT_EQ(2U, File->getSwiftABIVersion());
403 
404   SmallString<4096> Buffer;
405   raw_svector_ostream OS(Buffer);
406   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
407   EXPECT_TRUE(!WriteResult);
408   EXPECT_EQ(stripWhitespace(tbd_v3_swift_1_1), stripWhitespace(Buffer.c_str()));
409 }
410 
411 TEST(TBDv3, Swift_2_0) {
412   static const char tbd_v3_swift_2_0[] = "--- !tapi-tbd-v3\n"
413                                          "archs: [ arm64 ]\n"
414                                          "platform: ios\n"
415                                          "install-name: Test.dylib\n"
416                                          "swift-abi-version: 2.0\n"
417                                          "...\n";
418 
419   auto Result =
420       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_2_0, "Test.tbd"));
421   EXPECT_TRUE(!!Result);
422   auto File = std::move(Result.get());
423   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
424   EXPECT_EQ(3U, File->getSwiftABIVersion());
425 
426   SmallString<4096> Buffer;
427   raw_svector_ostream OS(Buffer);
428   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
429   EXPECT_TRUE(!WriteResult);
430   EXPECT_EQ(stripWhitespace(tbd_v3_swift_2_0), stripWhitespace(Buffer.c_str()));
431 }
432 
433 TEST(TBDv3, Swift_3_0) {
434   static const char tbd_v3_swift_3_0[] = "--- !tapi-tbd-v3\n"
435                                          "archs: [ arm64 ]\n"
436                                          "platform: ios\n"
437                                          "install-name: Test.dylib\n"
438                                          "swift-abi-version: 3.0\n"
439                                          "...\n";
440 
441   auto Result =
442       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_3_0, "Test.tbd"));
443   EXPECT_TRUE(!!Result);
444   auto File = std::move(Result.get());
445   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
446   EXPECT_EQ(4U, File->getSwiftABIVersion());
447 
448   SmallString<4096> Buffer;
449   raw_svector_ostream OS(Buffer);
450   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
451   EXPECT_TRUE(!WriteResult);
452   EXPECT_EQ(stripWhitespace(tbd_v3_swift_3_0), stripWhitespace(Buffer.c_str()));
453 }
454 
455 TEST(TBDv3, Swift_4_0) {
456   static const char tbd_v3_swift_4_0[] = "--- !tapi-tbd-v3\n"
457                                          "archs: [ arm64 ]\n"
458                                          "platform: ios\n"
459                                          "install-name: Test.dylib\n"
460                                          "swift-abi-version: 4.0\n"
461                                          "...\n";
462 
463   auto Result =
464       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_4_0, "Test.tbd"));
465   EXPECT_FALSE(!!Result);
466   auto errorMessage = toString(Result.takeError());
467   EXPECT_EQ("malformed file\nTest.tbd:5:20: error: invalid Swift ABI "
468             "version.\nswift-abi-version: 4.0\n                   ^~~\n",
469             errorMessage);
470 }
471 
472 TEST(TBDv3, Swift_5) {
473   static const char tbd_v3_swift_5[] = "--- !tapi-tbd-v3\n"
474                                        "archs: [ arm64 ]\n"
475                                        "platform: ios\n"
476                                        "install-name: Test.dylib\n"
477                                        "swift-abi-version: 5\n"
478                                        "...\n";
479 
480   auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_5, "Test.tbd"));
481   EXPECT_TRUE(!!Result);
482   auto File = std::move(Result.get());
483   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
484   EXPECT_EQ(5U, File->getSwiftABIVersion());
485 }
486 
487 TEST(TBDv3, Swift_99) {
488   static const char tbd_v3_swift_99[] = "--- !tapi-tbd-v3\n"
489                                         "archs: [ arm64 ]\n"
490                                         "platform: ios\n"
491                                         "install-name: Test.dylib\n"
492                                         "swift-abi-version: 99\n"
493                                         "...\n";
494 
495   auto Result =
496       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_99, "Test.tbd"));
497   EXPECT_TRUE(!!Result);
498   auto File = std::move(Result.get());
499   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
500   EXPECT_EQ(99U, File->getSwiftABIVersion());
501 }
502 
503 TEST(TBDv3, UnknownArchitecture) {
504   static const char tbd_v3_file_unknown_architecture[] =
505       "--- !tapi-tbd-v3\n"
506       "archs: [ foo ]\n"
507       "platform: macosx\n"
508       "install-name: Test.dylib\n"
509       "...\n";
510 
511   auto Result = TextAPIReader::get(
512       MemoryBufferRef(tbd_v3_file_unknown_architecture, "Test.tbd"));
513   EXPECT_TRUE(!!Result);
514 }
515 
516 TEST(TBDv3, UnknownPlatform) {
517   static const char tbd_v3_file_unknown_platform[] = "--- !tapi-tbd-v3\n"
518                                                      "archs: [ i386 ]\n"
519                                                      "platform: newOS\n"
520                                                      "...\n";
521 
522   auto Result = TextAPIReader::get(
523       MemoryBufferRef(tbd_v3_file_unknown_platform, "Test.tbd"));
524   EXPECT_FALSE(!!Result);
525   auto errorMessage = toString(Result.takeError());
526   EXPECT_EQ("malformed file\nTest.tbd:3:11: error: unknown platform\nplatform: "
527             "newOS\n          ^~~~~\n",
528             errorMessage);
529 }
530 
531 TEST(TBDv3, MalformedFile1) {
532   static const char malformed_file1[] = "--- !tapi-tbd-v3\n"
533                                         "archs: [ arm64 ]\n"
534                                         "foobar: \"Unsupported key\"\n"
535                                         "...\n";
536 
537   auto Result =
538       TextAPIReader::get(MemoryBufferRef(malformed_file1, "Test.tbd"));
539   EXPECT_FALSE(!!Result);
540   auto errorMessage = toString(Result.takeError());
541   ASSERT_EQ("malformed file\nTest.tbd:2:1: error: missing required key "
542             "'platform'\narchs: [ arm64 ]\n^\n",
543             errorMessage);
544 }
545 
546 TEST(TBDv3, MalformedFile2) {
547   static const char malformed_file2[] = "--- !tapi-tbd-v3\n"
548                                         "archs: [ arm64 ]\n"
549                                         "platform: ios\n"
550                                         "install-name: Test.dylib\n"
551                                         "foobar: \"Unsupported key\"\n"
552                                         "...\n";
553 
554   auto Result =
555       TextAPIReader::get(MemoryBufferRef(malformed_file2, "Test.tbd"));
556   EXPECT_FALSE(!!Result);
557   auto errorMessage = toString(Result.takeError());
558   ASSERT_EQ(
559       "malformed file\nTest.tbd:5:9: error: unknown key 'foobar'\nfoobar: "
560       "\"Unsupported key\"\n        ^~~~~~~~~~~~~~~~~\n",
561       errorMessage);
562 }
563 
564 } // namespace TBDv3
565