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, Platform_iOSSim) {
368   static const char tbd_v3_platform_iossim[] = "--- !tapi-tbd-v3\n"
369                                                "archs: [ x86_64 ]\n"
370                                                "platform: ios\n"
371                                                "install-name: Test.dylib\n"
372                                                "...\n";
373 
374   auto Result =
375       TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_iossim, "Test.tbd"));
376   EXPECT_TRUE(!!Result);
377   auto Platform = PlatformKind::iOSSimulator;
378   auto File = std::move(Result.get());
379   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
380   EXPECT_EQ(File->getPlatforms().size(), 1U);
381   EXPECT_EQ(Platform, *File->getPlatforms().begin());
382 
383   SmallString<4096> Buffer;
384   raw_svector_ostream OS(Buffer);
385   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
386   EXPECT_TRUE(!WriteResult);
387   EXPECT_EQ(stripWhitespace(tbd_v3_platform_iossim),
388             stripWhitespace(Buffer.c_str()));
389 }
390 
391 TEST(TBDv3, Platform_watchOSSim) {
392   static const char tbd_v3_platform_watchossim[] = "--- !tapi-tbd-v3\n"
393                                                    "archs: [ x86_64 ]\n"
394                                                    "platform: watchos\n"
395                                                    "install-name: Test.dylib\n"
396                                                    "...\n";
397 
398   auto Result = TextAPIReader::get(
399       MemoryBufferRef(tbd_v3_platform_watchossim, "Test.tbd"));
400   EXPECT_TRUE(!!Result);
401   auto Platform = PlatformKind::watchOSSimulator;
402   auto File = std::move(Result.get());
403   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
404   EXPECT_EQ(File->getPlatforms().size(), 1U);
405   EXPECT_EQ(Platform, *File->getPlatforms().begin());
406 
407   SmallString<4096> Buffer;
408   raw_svector_ostream OS(Buffer);
409   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
410   EXPECT_TRUE(!WriteResult);
411   EXPECT_EQ(stripWhitespace(tbd_v3_platform_watchossim),
412             stripWhitespace(Buffer.c_str()));
413 }
414 
415 TEST(TBDv3, Platform_tvOSSim) {
416   static const char tbd_v3_platform_tvossim[] = "--- !tapi-tbd-v3\n"
417                                                 "archs: [ x86_64 ]\n"
418                                                 "platform: tvos\n"
419                                                 "install-name: Test.dylib\n"
420                                                 "...\n";
421 
422   auto Result =
423       TextAPIReader::get(MemoryBufferRef(tbd_v3_platform_tvossim, "Test.tbd"));
424   EXPECT_TRUE(!!Result);
425   auto File = std::move(Result.get());
426   auto Platform = PlatformKind::tvOSSimulator;
427   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
428   EXPECT_EQ(File->getPlatforms().size(), 1U);
429   EXPECT_EQ(Platform, *File->getPlatforms().begin());
430 
431   SmallString<4096> Buffer;
432   raw_svector_ostream OS(Buffer);
433   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
434   EXPECT_TRUE(!WriteResult);
435   EXPECT_EQ(stripWhitespace(tbd_v3_platform_tvossim),
436             stripWhitespace(Buffer.c_str()));
437 }
438 
439 TEST(TBDv3, Swift_1_0) {
440   static const char tbd_v3_swift_1_0[] = "--- !tapi-tbd-v3\n"
441                                          "archs: [ arm64 ]\n"
442                                          "platform: ios\n"
443                                          "install-name: Test.dylib\n"
444                                          "swift-abi-version: 1.0\n"
445                                          "...\n";
446 
447   auto Result =
448       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_1_0, "Test.tbd"));
449   EXPECT_TRUE(!!Result);
450   auto File = std::move(Result.get());
451   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
452   EXPECT_EQ(1U, File->getSwiftABIVersion());
453 
454   SmallString<4096> Buffer;
455   raw_svector_ostream OS(Buffer);
456   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
457   EXPECT_TRUE(!WriteResult);
458   EXPECT_EQ(stripWhitespace(tbd_v3_swift_1_0), stripWhitespace(Buffer.c_str()));
459 }
460 
461 TEST(TBDv3, Swift_1_1) {
462   static const char tbd_v3_swift_1_1[] = "--- !tapi-tbd-v3\n"
463                                          "archs: [ arm64 ]\n"
464                                          "platform: ios\n"
465                                          "install-name: Test.dylib\n"
466                                          "swift-abi-version: 1.1\n"
467                                          "...\n";
468 
469   auto Result =
470       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_1_1, "Test.tbd"));
471   EXPECT_TRUE(!!Result);
472   auto File = std::move(Result.get());
473   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
474   EXPECT_EQ(2U, File->getSwiftABIVersion());
475 
476   SmallString<4096> Buffer;
477   raw_svector_ostream OS(Buffer);
478   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
479   EXPECT_TRUE(!WriteResult);
480   EXPECT_EQ(stripWhitespace(tbd_v3_swift_1_1), stripWhitespace(Buffer.c_str()));
481 }
482 
483 TEST(TBDv3, Swift_2_0) {
484   static const char tbd_v3_swift_2_0[] = "--- !tapi-tbd-v3\n"
485                                          "archs: [ arm64 ]\n"
486                                          "platform: ios\n"
487                                          "install-name: Test.dylib\n"
488                                          "swift-abi-version: 2.0\n"
489                                          "...\n";
490 
491   auto Result =
492       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_2_0, "Test.tbd"));
493   EXPECT_TRUE(!!Result);
494   auto File = std::move(Result.get());
495   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
496   EXPECT_EQ(3U, File->getSwiftABIVersion());
497 
498   SmallString<4096> Buffer;
499   raw_svector_ostream OS(Buffer);
500   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
501   EXPECT_TRUE(!WriteResult);
502   EXPECT_EQ(stripWhitespace(tbd_v3_swift_2_0), stripWhitespace(Buffer.c_str()));
503 }
504 
505 TEST(TBDv3, Swift_3_0) {
506   static const char tbd_v3_swift_3_0[] = "--- !tapi-tbd-v3\n"
507                                          "archs: [ arm64 ]\n"
508                                          "platform: ios\n"
509                                          "install-name: Test.dylib\n"
510                                          "swift-abi-version: 3.0\n"
511                                          "...\n";
512 
513   auto Result =
514       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_3_0, "Test.tbd"));
515   EXPECT_TRUE(!!Result);
516   auto File = std::move(Result.get());
517   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
518   EXPECT_EQ(4U, File->getSwiftABIVersion());
519 
520   SmallString<4096> Buffer;
521   raw_svector_ostream OS(Buffer);
522   auto WriteResult = TextAPIWriter::writeToStream(OS, *File);
523   EXPECT_TRUE(!WriteResult);
524   EXPECT_EQ(stripWhitespace(tbd_v3_swift_3_0), stripWhitespace(Buffer.c_str()));
525 }
526 
527 TEST(TBDv3, Swift_4_0) {
528   static const char tbd_v3_swift_4_0[] = "--- !tapi-tbd-v3\n"
529                                          "archs: [ arm64 ]\n"
530                                          "platform: ios\n"
531                                          "install-name: Test.dylib\n"
532                                          "swift-abi-version: 4.0\n"
533                                          "...\n";
534 
535   auto Result =
536       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_4_0, "Test.tbd"));
537   EXPECT_FALSE(!!Result);
538   auto errorMessage = toString(Result.takeError());
539   EXPECT_EQ("malformed file\nTest.tbd:5:20: error: invalid Swift ABI "
540             "version.\nswift-abi-version: 4.0\n                   ^~~\n",
541             errorMessage);
542 }
543 
544 TEST(TBDv3, Swift_5) {
545   static const char tbd_v3_swift_5[] = "--- !tapi-tbd-v3\n"
546                                        "archs: [ arm64 ]\n"
547                                        "platform: ios\n"
548                                        "install-name: Test.dylib\n"
549                                        "swift-abi-version: 5\n"
550                                        "...\n";
551 
552   auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_5, "Test.tbd"));
553   EXPECT_TRUE(!!Result);
554   auto File = std::move(Result.get());
555   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
556   EXPECT_EQ(5U, File->getSwiftABIVersion());
557 }
558 
559 TEST(TBDv3, Swift_99) {
560   static const char tbd_v3_swift_99[] = "--- !tapi-tbd-v3\n"
561                                         "archs: [ arm64 ]\n"
562                                         "platform: ios\n"
563                                         "install-name: Test.dylib\n"
564                                         "swift-abi-version: 99\n"
565                                         "...\n";
566 
567   auto Result =
568       TextAPIReader::get(MemoryBufferRef(tbd_v3_swift_99, "Test.tbd"));
569   EXPECT_TRUE(!!Result);
570   auto File = std::move(Result.get());
571   EXPECT_EQ(FileType::TBD_V3, File->getFileType());
572   EXPECT_EQ(99U, File->getSwiftABIVersion());
573 }
574 
575 TEST(TBDv3, UnknownArchitecture) {
576   static const char tbd_v3_file_unknown_architecture[] =
577       "--- !tapi-tbd-v3\n"
578       "archs: [ foo ]\n"
579       "platform: macosx\n"
580       "install-name: Test.dylib\n"
581       "...\n";
582 
583   auto Result = TextAPIReader::get(
584       MemoryBufferRef(tbd_v3_file_unknown_architecture, "Test.tbd"));
585   EXPECT_TRUE(!!Result);
586 }
587 
588 TEST(TBDv3, UnknownPlatform) {
589   static const char tbd_v3_file_unknown_platform[] = "--- !tapi-tbd-v3\n"
590                                                      "archs: [ i386 ]\n"
591                                                      "platform: newOS\n"
592                                                      "...\n";
593 
594   auto Result = TextAPIReader::get(
595       MemoryBufferRef(tbd_v3_file_unknown_platform, "Test.tbd"));
596   EXPECT_FALSE(!!Result);
597   auto errorMessage = toString(Result.takeError());
598   EXPECT_EQ("malformed file\nTest.tbd:3:11: error: unknown platform\nplatform: "
599             "newOS\n          ^~~~~\n",
600             errorMessage);
601 }
602 
603 TEST(TBDv3, MalformedFile1) {
604   static const char malformed_file1[] = "--- !tapi-tbd-v3\n"
605                                         "archs: [ arm64 ]\n"
606                                         "foobar: \"Unsupported key\"\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             "'platform'\narchs: [ arm64 ]\n^\n",
615             errorMessage);
616 }
617 
618 TEST(TBDv3, MalformedFile2) {
619   static const char malformed_file2[] = "--- !tapi-tbd-v3\n"
620                                         "archs: [ arm64 ]\n"
621                                         "platform: ios\n"
622                                         "install-name: Test.dylib\n"
623                                         "foobar: \"Unsupported key\"\n"
624                                         "...\n";
625 
626   auto Result =
627       TextAPIReader::get(MemoryBufferRef(malformed_file2, "Test.tbd"));
628   EXPECT_FALSE(!!Result);
629   auto errorMessage = toString(Result.takeError());
630   ASSERT_EQ(
631       "malformed file\nTest.tbd:5:9: error: unknown key 'foobar'\nfoobar: "
632       "\"Unsupported key\"\n        ^~~~~~~~~~~~~~~~~\n",
633       errorMessage);
634 }
635 
636 } // namespace TBDv3
637