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(ExportedSymbol{Sym->getKind(), Sym->getName(),
133                                         Sym->isWeakDefined(),
134                                         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   // It's not currently possible to emit the iomac platform. Enable this once
333   // that's fixed.
334 #if 0
335   SmallString<4096> Buffer;
336   raw_svector_ostream OS(Buffer);
337   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
338   EXPECT_TRUE(!WriteResult);
339   EXPECT_EQ(stripWhitespace(tbd_v3_platform_iosmac), stripWhitespace(Buffer.c_str()));
340 #endif
341 }
342 
343 TEST(TBDv3, Platform_zippered) {
344   static const char tbd_v3_platform_zip[] = "--- !tapi-tbd-v3\n"
345                                                  "archs: [ armv7k ]\n"
346                                                  "platform: zippered\n"
347                                                  "install-name: Test.dylib\n"
348                                                  "...\n";
349 
350   auto Result =
351       TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_zip, "Test.tbd"));
352   EXPECT_TRUE(!!Result);
353   auto File = std::move(Result.get());
354   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
355 
356   PlatformSet Platforms;
357   Platforms.insert(PlatformKind::macOS);
358   Platforms.insert(PlatformKind::macCatalyst);
359   EXPECT_EQ(Platforms.size(), File->getPlatforms().size());
360   for (auto Platform : File->getPlatforms())
361 	    EXPECT_EQ(Platforms.count(Platform), 1U);
362 
363   SmallString<4096> Buffer;
364   raw_svector_ostream OS(Buffer);
365   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
366   EXPECT_TRUE(!WriteResult);
367   EXPECT_EQ(stripWhitespace(tbd_v3_platform_zip),
368             stripWhitespace(Buffer.c_str()));
369 }
370 
371 TEST(TBDv3, Swift_1_0) {
372   static const char tbd_v3_swift_1_0[] = "--- !tapi-tbd-v3\n"
373                                          "archs: [ arm64 ]\n"
374                                          "platform: ios\n"
375                                          "install-name: Test.dylib\n"
376                                          "swift-abi-version: 1.0\n"
377                                          "...\n";
378 
379   auto Result =
380       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_1_0, "Test.tbd"));
381   EXPECT_TRUE(!!Result);
382   auto File = std::move(Result.get());
383   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
384   EXPECT_EQ(1U, File->getSwiftABIVersion());
385 
386   SmallString<4096> Buffer;
387   raw_svector_ostream OS(Buffer);
388   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
389   EXPECT_TRUE(!WriteResult);
390   EXPECT_EQ(stripWhitespace(tbd_v3_swift_1_0), stripWhitespace(Buffer.c_str()));
391 }
392 
393 TEST(TBDv3, Swift_1_1) {
394   static const char tbd_v3_swift_1_1[] = "--- !tapi-tbd-v3\n"
395                                          "archs: [ arm64 ]\n"
396                                          "platform: ios\n"
397                                          "install-name: Test.dylib\n"
398                                          "swift-abi-version: 1.1\n"
399                                          "...\n";
400 
401   auto Result =
402       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_1_1, "Test.tbd"));
403   EXPECT_TRUE(!!Result);
404   auto File = std::move(Result.get());
405   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
406   EXPECT_EQ(2U, File->getSwiftABIVersion());
407 
408   SmallString<4096> Buffer;
409   raw_svector_ostream OS(Buffer);
410   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
411   EXPECT_TRUE(!WriteResult);
412   EXPECT_EQ(stripWhitespace(tbd_v3_swift_1_1), stripWhitespace(Buffer.c_str()));
413 }
414 
415 TEST(TBDv3, Swift_2_0) {
416   static const char tbd_v3_swift_2_0[] = "--- !tapi-tbd-v3\n"
417                                          "archs: [ arm64 ]\n"
418                                          "platform: ios\n"
419                                          "install-name: Test.dylib\n"
420                                          "swift-abi-version: 2.0\n"
421                                          "...\n";
422 
423   auto Result =
424       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_2_0, "Test.tbd"));
425   EXPECT_TRUE(!!Result);
426   auto File = std::move(Result.get());
427   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
428   EXPECT_EQ(3U, File->getSwiftABIVersion());
429 
430   SmallString<4096> Buffer;
431   raw_svector_ostream OS(Buffer);
432   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
433   EXPECT_TRUE(!WriteResult);
434   EXPECT_EQ(stripWhitespace(tbd_v3_swift_2_0), stripWhitespace(Buffer.c_str()));
435 }
436 
437 TEST(TBDv3, Swift_3_0) {
438   static const char tbd_v3_swift_3_0[] = "--- !tapi-tbd-v3\n"
439                                          "archs: [ arm64 ]\n"
440                                          "platform: ios\n"
441                                          "install-name: Test.dylib\n"
442                                          "swift-abi-version: 3.0\n"
443                                          "...\n";
444 
445   auto Result =
446       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_3_0, "Test.tbd"));
447   EXPECT_TRUE(!!Result);
448   auto File = std::move(Result.get());
449   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
450   EXPECT_EQ(4U, File->getSwiftABIVersion());
451 
452   SmallString<4096> Buffer;
453   raw_svector_ostream OS(Buffer);
454   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
455   EXPECT_TRUE(!WriteResult);
456   EXPECT_EQ(stripWhitespace(tbd_v3_swift_3_0), stripWhitespace(Buffer.c_str()));
457 }
458 
459 TEST(TBDv3, Swift_4_0) {
460   static const char tbd_v3_swift_4_0[] = "--- !tapi-tbd-v3\n"
461                                          "archs: [ arm64 ]\n"
462                                          "platform: ios\n"
463                                          "install-name: Test.dylib\n"
464                                          "swift-abi-version: 4.0\n"
465                                          "...\n";
466 
467   auto Result =
468       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_4_0, "Test.tbd"));
469   EXPECT_FALSE(!!Result);
470   auto errorMessage = toString(Result.takeError());
471   EXPECT_EQ("malformed file\nTest.tbd:5:20: error: invalid Swift ABI "
472             "version.\nswift-abi-version: 4.0\n                   ^~~\n",
473             errorMessage);
474 }
475 
476 TEST(TBDv3, Swift_5) {
477   static const char tbd_v3_swift_5[] = "--- !tapi-tbd-v3\n"
478                                        "archs: [ arm64 ]\n"
479                                        "platform: ios\n"
480                                        "install-name: Test.dylib\n"
481                                        "swift-abi-version: 5\n"
482                                        "...\n";
483 
484   auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_5, "Test.tbd"));
485   EXPECT_TRUE(!!Result);
486   auto File = std::move(Result.get());
487   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
488   EXPECT_EQ(5U, File->getSwiftABIVersion());
489 }
490 
491 TEST(TBDv3, Swift_99) {
492   static const char tbd_v3_swift_99[] = "--- !tapi-tbd-v3\n"
493                                         "archs: [ arm64 ]\n"
494                                         "platform: ios\n"
495                                         "install-name: Test.dylib\n"
496                                         "swift-abi-version: 99\n"
497                                         "...\n";
498 
499   auto Result =
500       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_99, "Test.tbd"));
501   EXPECT_TRUE(!!Result);
502   auto File = std::move(Result.get());
503   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
504   EXPECT_EQ(99U, File->getSwiftABIVersion());
505 }
506 
507 TEST(TBDv3, UnknownArchitecture) {
508   static const char tbd_v3_file_unknown_architecture[] =
509       "--- !tapi-tbd-v3\n"
510       "archs: [ foo ]\n"
511       "platform: macosx\n"
512       "install-name: Test.dylib\n"
513       "...\n";
514 
515   auto Result = TextAPIReader::get(
516       MemoryBufferRef(tbd_v3_file_unknown_architecture, "Test.tbd"));
517   EXPECT_TRUE(!!Result);
518 }
519 
520 TEST(TBDv3, UnknownPlatform) {
521   static const char tbd_v3_file_unknown_platform[] = "--- !tapi-tbd-v3\n"
522                                                      "archs: [ i386 ]\n"
523                                                      "platform: newOS\n"
524                                                      "...\n";
525 
526   auto Result = TextAPIReader::get(
527       MemoryBufferRef(tbd_v3_file_unknown_platform, "Test.tbd"));
528   EXPECT_FALSE(!!Result);
529   auto errorMessage = toString(Result.takeError());
530   EXPECT_EQ("malformed file\nTest.tbd:3:11: error: unknown platform\nplatform: "
531             "newOS\n          ^~~~~\n",
532             errorMessage);
533 }
534 
535 TEST(TBDv3, MalformedFile1) {
536   static const char malformed_file1[] = "--- !tapi-tbd-v3\n"
537                                         "archs: [ arm64 ]\n"
538                                         "foobar: \"Unsupported key\"\n"
539                                         "...\n";
540 
541   auto Result =
542       TextAPIReader::get(MemoryBufferRef(malformed_file1, "Test.tbd"));
543   EXPECT_FALSE(!!Result);
544   auto errorMessage = toString(Result.takeError());
545   ASSERT_EQ("malformed file\nTest.tbd:2:1: error: missing required key "
546             "'platform'\narchs: [ arm64 ]\n^\n",
547             errorMessage);
548 }
549 
550 TEST(TBDv3, MalformedFile2) {
551   static const char malformed_file2[] = "--- !tapi-tbd-v3\n"
552                                         "archs: [ arm64 ]\n"
553                                         "platform: ios\n"
554                                         "install-name: Test.dylib\n"
555                                         "foobar: \"Unsupported key\"\n"
556                                         "...\n";
557 
558   auto Result =
559       TextAPIReader::get(MemoryBufferRef(malformed_file2, "Test.tbd"));
560   EXPECT_FALSE(!!Result);
561   auto errorMessage = toString(Result.takeError());
562   ASSERT_EQ(
563       "malformed file\nTest.tbd:5:9: error: unknown key 'foobar'\nfoobar: "
564       "\"Unsupported key\"\n        ^~~~~~~~~~~~~~~~~\n",
565       errorMessage);
566 }
567 
568 } // namespace TBDv3
569