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