xref: /llvm-project/llvm/unittests/TextAPI/TextStubV5Tests.cpp (revision 397486566e995a019c249784b1d07c53b6ac670d)
1 //===-- TextStubV5Tests.cpp - TBD V5 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 "TextStubHelpers.h"
10 #include "llvm/TextAPI/InterfaceFile.h"
11 #include "llvm/TextAPI/TextAPIReader.h"
12 #include "llvm/TextAPI/TextAPIWriter.h"
13 #include "gtest/gtest.h"
14 #include <string>
15 #include <vector>
16 
17 using namespace llvm;
18 using namespace llvm::MachO;
19 
20 namespace TBDv5 {
21 
22 TEST(TBDv5, ReadFile) {
23   static const char TBDv5File[] = R"({
24 "tapi_tbd_version": 5,
25 "main_library": {
26   "target_info": [
27     {
28       "target": "x86_64-macos",
29       "min_deployment": "10.14"
30     },
31     {
32       "target": "arm64-macos",
33       "min_deployment": "10.14"
34     },
35     {
36       "target": "arm64-maccatalyst",
37       "min_deployment": "12.1"
38     }
39   ],
40   "flags": [
41     {
42       "targets": [
43             "x86_64-macos"
44         ],
45       "attributes": [
46             "flat_namespace"
47         ]
48     }
49   ],
50   "install_names": [
51     {
52         "name": "/S/L/F/Foo.framework/Foo"
53     }
54   ],
55   "current_versions": [
56     {
57         "version": "1.2"
58     }
59   ],
60   "compatibility_versions": [
61     { "version": "1.1" }
62   ],
63   "rpaths": [
64     {
65       "targets": [
66           "x86_64-macos"
67       ],
68       "paths": [
69           "@executable_path/.../Frameworks"
70       ]
71     }
72   ],
73   "parent_umbrellas": [
74     {
75       "umbrella": "System"
76     }
77   ],
78   "allowable_clients": [
79     {
80         "clients": [
81             "ClientA",
82             "ClientB"
83         ]
84     }
85   ],
86   "reexported_libraries": [
87     {
88         "names": [
89             "/u/l/l/libfoo.dylib",
90             "/u/l/l/libbar.dylib"
91         ]
92     }
93   ],
94   "exported_symbols": [
95     {
96         "targets": [
97             "x86_64-macos",
98             "arm64-macos"
99         ],
100         "data": {
101             "global": [
102                 "_global"
103             ],
104             "objc_class": [
105                 "ClassA"
106             ],
107             "weak": [],
108             "thread_local": []
109         },
110         "text": {
111             "global": [
112                 "_func"
113             ],
114             "weak": [],
115             "thread_local": []
116         }
117     },
118     {
119       "targets": [
120           "x86_64-macos"
121       ],
122       "data": {
123           "global": [
124               "_globalVar"
125           ],
126           "objc_class": [
127               "ClassData"
128           ],
129           "objc_eh_type": [
130               "ClassA",
131               "ClassB"
132           ],
133           "objc_ivar": [
134               "ClassA.ivar1",
135               "ClassA.ivar2",
136               "ClassC.ivar1"
137           ]
138       },
139       "text": {
140           "global": [
141               "_funcFoo"
142           ]
143       }
144     }
145   ],
146   "reexported_symbols": [
147     {
148         "targets": [
149             "x86_64-macos",
150             "arm64-macos"
151         ],
152         "data": {
153             "global": [
154                 "_globalRe"
155             ],
156             "objc_class": [
157                 "ClassRexport"
158             ]
159         },
160         "text": {
161             "global": [
162                 "_funcA"
163             ]
164         }
165     }
166   ],
167   "undefined_symbols": [
168     {
169         "targets": [
170             "x86_64-macos"
171         ],
172         "data": {
173             "global": [
174                 "_globalBind"
175             ],
176             "weak": [
177                 "referenced_sym"
178             ]
179         }
180     }
181   ]
182 },
183 "libraries": []
184 })";
185 
186   Expected<TBDFile> Result =
187       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
188   EXPECT_TRUE(!!Result);
189   TBDFile File = std::move(Result.get());
190   EXPECT_EQ(FileType::TBD_V5, File->getFileType());
191   EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName());
192 
193   TargetList AllTargets = {
194       Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
195       Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)),
196       Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)),
197   };
198   EXPECT_EQ(mapToPlatformSet(AllTargets), File->getPlatforms());
199   EXPECT_EQ(mapToArchitectureSet(AllTargets), File->getArchitectures());
200 
201   EXPECT_EQ(PackedVersion(1, 2, 0), File->getCurrentVersion());
202   EXPECT_EQ(PackedVersion(1, 1, 0), File->getCompatibilityVersion());
203   EXPECT_TRUE(File->isApplicationExtensionSafe());
204   EXPECT_FALSE(File->isTwoLevelNamespace());
205   EXPECT_EQ(0U, File->documents().size());
206 
207   InterfaceFileRef ClientA("ClientA", AllTargets);
208   InterfaceFileRef ClientB("ClientB", AllTargets);
209   EXPECT_EQ(2U, File->allowableClients().size());
210   EXPECT_EQ(ClientA, File->allowableClients().at(0));
211   EXPECT_EQ(ClientB, File->allowableClients().at(1));
212 
213   InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
214   InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
215   EXPECT_EQ(2U, File->reexportedLibraries().size());
216   EXPECT_EQ(ReexportA, File->reexportedLibraries().at(0));
217   EXPECT_EQ(ReexportB, File->reexportedLibraries().at(1));
218 
219   TargetToAttr RPaths = {
220       {Target(AK_x86_64, PLATFORM_MACOS), "@executable_path/.../Frameworks"},
221   };
222   EXPECT_EQ(RPaths, File->rpaths());
223 
224   TargetToAttr Umbrellas = {{Target(AK_x86_64, PLATFORM_MACOS), "System"},
225                             {Target(AK_arm64, PLATFORM_MACOS), "System"},
226                             {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}};
227   EXPECT_EQ(Umbrellas, File->umbrellas());
228 
229   ExportedSymbolSeq Exports, Reexports, Undefineds;
230   for (const auto *Sym : File->symbols()) {
231     TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()};
232     ExportedSymbol Temp =
233         ExportedSymbol{Sym->getKind(),
234                        std::string(Sym->getName()),
235                        Sym->isWeakDefined() || Sym->isWeakReferenced(),
236                        Sym->isThreadLocalValue(),
237                        Sym->isData(),
238                        SymTargets};
239     if (Sym->isUndefined())
240       Undefineds.emplace_back(std::move(Temp));
241     else
242       Sym->isReexported() ? Reexports.emplace_back(std::move(Temp))
243                           : Exports.emplace_back(std::move(Temp));
244   }
245   llvm::sort(Exports);
246   llvm::sort(Reexports);
247   llvm::sort(Undefineds);
248 
249   TargetList MacOSTargets = {Target(AK_x86_64, PLATFORM_MACOS),
250                              Target(AK_arm64, PLATFORM_MACOS)};
251 
252   std::vector<ExportedSymbol> ExpectedExportedSymbols = {
253       {SymbolKind::GlobalSymbol, "_func", false, false, false, MacOSTargets},
254       {SymbolKind::GlobalSymbol,
255        "_funcFoo",
256        false,
257        false,
258        false,
259        {Target(AK_x86_64, PLATFORM_MACOS)}},
260       {SymbolKind::GlobalSymbol, "_global", false, false, true, MacOSTargets},
261       {SymbolKind::GlobalSymbol,
262        "_globalVar",
263        false,
264        false,
265        true,
266        {Target(AK_x86_64, PLATFORM_MACOS)}},
267       {SymbolKind::ObjectiveCClass, "ClassA", false, false, true, MacOSTargets},
268       {SymbolKind::ObjectiveCClass,
269        "ClassData",
270        false,
271        false,
272        true,
273        {Target(AK_x86_64, PLATFORM_MACOS)}},
274       {SymbolKind::ObjectiveCClassEHType,
275        "ClassA",
276        false,
277        false,
278        true,
279        {Target(AK_x86_64, PLATFORM_MACOS)}},
280       {SymbolKind::ObjectiveCClassEHType,
281        "ClassB",
282        false,
283        false,
284        true,
285        {Target(AK_x86_64, PLATFORM_MACOS)}},
286       {SymbolKind::ObjectiveCInstanceVariable,
287        "ClassA.ivar1",
288        false,
289        false,
290        true,
291        {Target(AK_x86_64, PLATFORM_MACOS)}},
292       {SymbolKind::ObjectiveCInstanceVariable,
293        "ClassA.ivar2",
294        false,
295        false,
296        true,
297        {Target(AK_x86_64, PLATFORM_MACOS)}},
298       {SymbolKind::ObjectiveCInstanceVariable,
299        "ClassC.ivar1",
300        false,
301        false,
302        true,
303        {Target(AK_x86_64, PLATFORM_MACOS)}},
304   };
305   std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
306       {SymbolKind::GlobalSymbol, "_funcA", false, false, false, MacOSTargets},
307       {SymbolKind::GlobalSymbol, "_globalRe", false, false, true, MacOSTargets},
308       {SymbolKind::ObjectiveCClass, "ClassRexport", false, false, true,
309        MacOSTargets},
310   };
311 
312   std::vector<ExportedSymbol> ExpectedUndefinedSymbols = {
313       {SymbolKind::GlobalSymbol,
314        "_globalBind",
315        false,
316        false,
317        true,
318        {Target(AK_x86_64, PLATFORM_MACOS)}},
319       {SymbolKind::GlobalSymbol,
320        "referenced_sym",
321        true,
322        false,
323        true,
324        {Target(AK_x86_64, PLATFORM_MACOS)}},
325   };
326 
327   EXPECT_EQ(ExpectedExportedSymbols.size(), Exports.size());
328   EXPECT_EQ(ExpectedReexportedSymbols.size(), Reexports.size());
329   EXPECT_EQ(ExpectedUndefinedSymbols.size(), Undefineds.size());
330   EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
331                          std::begin(ExpectedExportedSymbols)));
332   EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
333                          std::begin(ExpectedReexportedSymbols)));
334   EXPECT_TRUE(std::equal(Undefineds.begin(), Undefineds.end(),
335                          std::begin(ExpectedUndefinedSymbols)));
336 }
337 
338 TEST(TBDv5, ReadMultipleTargets) {
339   static const char TBDv5File[] = R"({
340 "tapi_tbd_version": 5,
341 "main_library":  {
342   "target_info": [
343       {
344           "target": "x86_64-macos",
345           "min_deployment": "10.14"
346       },
347       {
348           "target": "arm64-macos",
349           "min_deployment": "10.14"
350       },
351       {
352           "target": "arm64-maccatalyst",
353           "min_deployment": "12.1"
354       }
355   ],
356   "install_names":[
357       { "name":"/usr/lib/libFoo.dylib" }
358   ],
359   "swift_abi":[ { "abi":8 } ],
360   "reexported_libraries": [
361       {
362           "targets": [ "x86_64-maccatalyst" ],
363           "names": [
364               "/u/l/l/libfoo.dylib",
365               "/u/l/l/libbar.dylib"
366           ]
367       },
368       {
369           "targets": [ "arm64-maccatalyst" ],
370           "names": [ "/u/l/l/libArmOnly.dylib" ]
371       }
372   ]
373 }
374 })";
375 
376   Expected<TBDFile> Result =
377       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
378   EXPECT_TRUE(!!Result);
379   TBDFile File = std::move(Result.get());
380   EXPECT_EQ(FileType::TBD_V5, File->getFileType());
381   EXPECT_EQ(std::string("/usr/lib/libFoo.dylib"), File->getInstallName());
382   EXPECT_TRUE(File->isApplicationExtensionSafe());
383   EXPECT_TRUE(File->isTwoLevelNamespace());
384   EXPECT_EQ(PackedVersion(1, 0, 0), File->getCurrentVersion());
385   EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());
386   EXPECT_EQ(8U, File->getSwiftABIVersion());
387 
388   TargetList AllTargets = {
389       Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
390       Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)),
391       Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)),
392   };
393   EXPECT_EQ(mapToPlatformSet(AllTargets), File->getPlatforms());
394   EXPECT_EQ(mapToArchitectureSet(AllTargets), File->getArchitectures());
395 
396   InterfaceFileRef ReexportA("/u/l/l/libArmOnly.dylib",
397                              {Target(AK_arm64, PLATFORM_MACCATALYST)});
398   InterfaceFileRef ReexportB("/u/l/l/libbar.dylib",
399                              {Target(AK_x86_64, PLATFORM_MACCATALYST)});
400   InterfaceFileRef ReexportC("/u/l/l/libfoo.dylib",
401                              {Target(AK_x86_64, PLATFORM_MACCATALYST)});
402   EXPECT_EQ(3U, File->reexportedLibraries().size());
403   EXPECT_EQ(ReexportA, File->reexportedLibraries().at(0));
404   EXPECT_EQ(ReexportB, File->reexportedLibraries().at(1));
405   EXPECT_EQ(ReexportC, File->reexportedLibraries().at(2));
406 }
407 
408 TEST(TBDv5, ReadMultipleDocuments) {
409   static const char TBDv5File[] = R"({
410 "tapi_tbd_version": 5,
411 "main_library": {
412   "target_info": [
413     {
414       "target": "armv7-ios",
415       "min_deployment": "11.0"
416     }
417   ],
418   "install_names":[
419     { "name":"/S/L/F/Foo.framework/Foo" }
420   ],
421   "reexported_libraries": [
422     { "names": ["/u/l/l/libfoo.dylib"] }
423   ]
424 },
425 "libraries": [
426   {
427     "target_info": [
428       {
429         "target": "armv7-ios",
430         "min_deployment": "11.0"
431       }
432     ],
433     "install_names":[
434       { "name":"/u/l/l/libfoo.dylib" }
435     ],
436     "flags":[
437       { "attributes": ["not_app_extension_safe"] }
438     ],
439     "exported_symbols": [
440       {
441         "data": {
442           "thread_local": [ "_globalVar" ],
443           "objc_class": [ "ClassData" ],
444           "objc_eh_type": [ "ClassA", "ClassB" ]
445         },
446         "text": {
447           "global": [ "_funcFoo" ]
448         }
449       }
450     ]
451   }
452 ]})";
453 
454   Expected<TBDFile> Result =
455       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
456   EXPECT_TRUE(!!Result);
457   TBDFile File = std::move(Result.get());
458   EXPECT_EQ(FileType::TBD_V5, File->getFileType());
459   EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName());
460   EXPECT_TRUE(File->isTwoLevelNamespace());
461   EXPECT_TRUE(File->isApplicationExtensionSafe());
462 
463   TargetList Targets(File->targets().begin(), File->targets().end());
464   Target iOSTarget(AK_armv7, PLATFORM_IOS, VersionTuple(11, 0));
465   EXPECT_EQ(TargetList{iOSTarget}, Targets);
466   std::vector<const Symbol *> Symbols(File->symbols().begin(),
467                                       File->symbols().end());
468   EXPECT_EQ(0U, Symbols.size());
469 
470   InterfaceFileRef Reexport("/u/l/l/libfoo.dylib", {iOSTarget});
471   EXPECT_EQ(1U, File->reexportedLibraries().size());
472   EXPECT_EQ(Reexport, File->reexportedLibraries().at(0));
473 
474   // Check inlined library.
475   EXPECT_EQ(1U, File->documents().size());
476   TBDReexportFile Document = File->documents().front();
477   Targets = {Document->targets().begin(), Document->targets().end()};
478   EXPECT_EQ(TargetList{iOSTarget}, Targets);
479   EXPECT_EQ(std::string("/u/l/l/libfoo.dylib"), Document->getInstallName());
480   EXPECT_EQ(0U, Document->getSwiftABIVersion());
481   EXPECT_TRUE(Document->isTwoLevelNamespace());
482   EXPECT_FALSE(Document->isApplicationExtensionSafe());
483 
484   ExportedSymbolSeq Exports;
485   for (const auto *Sym : Document->symbols())
486     Exports.emplace_back(
487         ExportedSymbol{Sym->getKind(),
488                        std::string(Sym->getName()),
489                        Sym->isWeakDefined() || Sym->isWeakReferenced(),
490                        Sym->isThreadLocalValue(),
491                        Sym->isData(),
492                        {iOSTarget}});
493 
494   llvm::sort(Exports);
495   ExportedSymbolSeq ExpectedExports = {
496       {SymbolKind::GlobalSymbol, "_funcFoo", false, false, false, {iOSTarget}},
497       {SymbolKind::GlobalSymbol, "_globalVar", false, true, true, {iOSTarget}},
498       {SymbolKind::ObjectiveCClass,
499        "ClassData",
500        false,
501        false,
502        true,
503        {iOSTarget}},
504       {SymbolKind::ObjectiveCClassEHType,
505        "ClassA",
506        false,
507        false,
508        true,
509        {iOSTarget}},
510       {SymbolKind::ObjectiveCClassEHType,
511        "ClassB",
512        false,
513        false,
514        true,
515        {iOSTarget}},
516   };
517 
518   EXPECT_EQ(ExpectedExports.size(), Exports.size());
519   EXPECT_TRUE(
520       std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports)));
521 }
522 
523 TEST(TBDv5, WriteFile) {
524   static const char TBDv5File[] = R"({
525 "tapi_tbd_version": 5,
526 "main_library": {
527   "target_info": [
528     {
529       "target": "x86_64-macos",
530       "min_deployment": "10.14"
531     },
532     {
533       "target": "arm64-macos",
534       "min_deployment": "10.14"
535     },
536     {
537       "target": "arm64-maccatalyst",
538       "min_deployment": "12.1"
539     }
540   ],
541   "install_names": [
542     {
543         "name": "@rpath/S/L/F/Foo.framework/Foo"
544     }
545   ],
546   "current_versions": [
547     {
548         "version": "1.2"
549     }
550   ],
551   "compatibility_versions": [
552     { "version": "1.1" }
553   ],
554   "flags": [
555     {
556       "attributes": [
557             "flat_namespace"
558         ]
559     }
560   ],
561   "rpaths": [
562     {
563       "targets": [
564           "x86_64-macos"
565       ],
566       "paths": [
567           "@executable_path/.../Frameworks"
568       ]
569     }
570   ],
571   "parent_umbrellas": [
572     {
573       "umbrella": "System"
574     }
575   ],
576   "allowable_clients": [
577     {
578         "clients": [
579             "ClientA",
580             "ClientB"
581         ]
582     }
583   ],
584   "reexported_libraries": [
585     {
586         "names": [
587             "/u/l/l/libfoo.dylib",
588             "/u/l/l/libbar.dylib"
589         ]
590     }
591   ],
592   "exported_symbols": [
593     {
594         "targets": [
595             "x86_64-macos",
596             "arm64-macos"
597         ],
598         "data": {
599             "global": [
600                 "_global"
601             ],
602             "objc_class": [
603                 "ClassA"
604             ],
605             "weak": [],
606             "thread_local": []
607         },
608         "text": {
609             "global": [
610                 "_func"
611             ],
612             "weak": [],
613             "thread_local": []
614         }
615     },
616     {
617       "targets": [
618           "x86_64-macos"
619       ],
620       "data": {
621           "global": [
622               "_globalVar"
623           ],
624           "objc_class": [
625               "ClassData"
626           ],
627           "objc_eh_type": [
628               "ClassA",
629               "ClassB"
630           ],
631           "objc_ivar": [
632               "ClassA.ivar1",
633               "ClassA.ivar2",
634               "ClassC.ivar1"
635           ]
636       },
637       "text": {
638           "global": [
639               "_funcFoo"
640           ]
641       }
642     }
643   ],
644   "reexported_symbols": [
645     {
646         "data": {
647             "global": [
648                 "_globalRe"
649             ],
650             "objc_class": [
651                 "ClassRexport"
652             ]
653         },
654         "text": {
655             "global": [
656                 "_funcA"
657             ]
658         }
659     }
660   ],
661   "undefined_symbols": [
662     {
663         "targets": [
664             "x86_64-macos"
665         ],
666         "data": {
667             "global": [
668                 "_globalBind"
669             ],
670             "weak": [
671                 "referenced_sym"
672             ]
673         }
674     }
675   ]
676 }})";
677 
678   InterfaceFile File;
679   File.setFileType(FileType::TBD_V5);
680 
681   TargetList AllTargets = {
682       Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
683       Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)),
684       Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)),
685   };
686   File.addTargets(AllTargets);
687   File.setInstallName("@rpath/S/L/F/Foo.framework/Foo");
688   File.setCurrentVersion(PackedVersion(1, 2, 0));
689   File.setCompatibilityVersion(PackedVersion(1, 1, 0));
690   File.addRPath(AllTargets[0], "@executable_path/.../Frameworks");
691 
692   for (const auto &Targ : AllTargets) {
693     File.addParentUmbrella(Targ, "System");
694     File.addAllowableClient("ClientA", Targ);
695     File.addAllowableClient("ClientB", Targ);
696     File.addReexportedLibrary("/u/l/l/libfoo.dylib", Targ);
697     File.addReexportedLibrary("/u/l/l/libbar.dylib", Targ);
698   }
699 
700   SymbolFlags Flags = SymbolFlags::None;
701   // Exports.
702   File.addSymbol(SymbolKind::GlobalSymbol, "_global",
703                  {AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Data);
704   File.addSymbol(SymbolKind::GlobalSymbol, "_func",
705                  {AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Text);
706   File.addSymbol(SymbolKind::ObjectiveCClass, "ClassA",
707                  {AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Data);
708   File.addSymbol(SymbolKind::GlobalSymbol, "_funcFoo", {AllTargets[0]},
709                  Flags | SymbolFlags::Text);
710   File.addSymbol(SymbolKind::GlobalSymbol, "_globalVar", {AllTargets[0]},
711                  Flags | SymbolFlags::Data);
712   File.addSymbol(SymbolKind::ObjectiveCClass, "ClassData", {AllTargets[0]},
713                  Flags | SymbolFlags::Data);
714   File.addSymbol(SymbolKind::ObjectiveCClassEHType, "ClassA", {AllTargets[0]},
715                  Flags | SymbolFlags::Data);
716   File.addSymbol(SymbolKind::ObjectiveCClassEHType, "ClassB", {AllTargets[0]},
717                  Flags | SymbolFlags::Data);
718   File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "ClassA.ivar1",
719                  {AllTargets[0]}, Flags | SymbolFlags::Data);
720   File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "ClassA.ivar2",
721                  {AllTargets[0]}, Flags | SymbolFlags::Data);
722   File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "ClassC.ivar1",
723                  {AllTargets[0]}, Flags | SymbolFlags::Data);
724 
725   // Reexports.
726   Flags = SymbolFlags::Rexported;
727   File.addSymbol(SymbolKind::GlobalSymbol, "_globalRe", AllTargets,
728                  Flags | SymbolFlags::Data);
729   File.addSymbol(SymbolKind::GlobalSymbol, "_funcA", AllTargets,
730                  Flags | SymbolFlags::Text);
731   File.addSymbol(SymbolKind::ObjectiveCClass, "ClassRexport", AllTargets,
732                  Flags | SymbolFlags::Data);
733 
734   // Undefineds.
735   Flags = SymbolFlags::Undefined;
736   File.addSymbol(SymbolKind::GlobalSymbol, "_globalBind", {AllTargets[0]},
737                  Flags | SymbolFlags::Data);
738   File.addSymbol(SymbolKind::GlobalSymbol, "referenced_sym", {AllTargets[0]},
739                  Flags | SymbolFlags::Data | SymbolFlags::WeakReferenced);
740 
741   File.setTwoLevelNamespace(false);
742   File.setApplicationExtensionSafe(true);
743 
744   // Write out file then process it back into IF and compare equality
745   // against TBDv5File.
746   SmallString<4096> Buffer;
747   raw_svector_ostream OS(Buffer);
748   Error Result = TextAPIWriter::writeToStream(OS, File);
749   EXPECT_FALSE(Result);
750 
751   Expected<TBDFile> Input =
752       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Input.tbd"));
753   EXPECT_TRUE(!!Input);
754   TBDFile InputFile = std::move(Input.get());
755 
756   Expected<TBDFile> Output =
757       TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
758   EXPECT_TRUE(!!Output);
759   TBDFile OutputFile = std::move(Output.get());
760   EXPECT_EQ(*InputFile, *OutputFile);
761 }
762 
763 TEST(TBDv5, WriteMultipleDocuments) {
764   static const char TBDv5File[] = R"({
765 "tapi_tbd_version": 5,
766 "main_library": {
767   "target_info": [
768     {
769       "target": "armv7-ios",
770       "min_deployment": "11.0"
771     }
772   ],
773   "install_names":[
774     { "name":"/S/L/F/Foo.framework/Foo" }
775   ],
776   "reexported_libraries": [
777     { "names": ["/u/l/l/libfoo.dylib"]
778     }
779   ]
780 },
781 "libraries": [
782   {
783     "target_info": [
784       {
785         "target": "armv7-ios",
786         "min_deployment": "11.0"
787       },
788       {
789         "target": "armv7s-ios",
790         "min_deployment": "11.0"
791       }
792     ],
793     "install_names":[
794       { "name":"/u/l/l/libfoo.dylib" }
795     ],
796     "current_versions": [
797       {
798           "version": "2.1.1"
799       }
800     ],
801     "rpaths": [
802       {
803         "targets": [
804             "armv7-ios"
805         ],
806         "paths": [
807             "@executable_path/.../Frameworks"
808         ]
809       }],
810     "reexported_libraries": [ { "names": ["@rpath/libfoo.dylib"] } ],
811     "flags":[
812       { "attributes": ["not_app_extension_safe"] }
813     ],
814     "exported_symbols": [
815       {
816         "text": {
817           "global": [ "_funcFoo" ]
818         }
819       }
820     ]
821   },
822   {
823     "target_info": [
824       {
825         "target": "armv7-ios",
826         "min_deployment": "11.0"
827       }
828     ],
829     "install_names":[
830       { "name":"@rpath/libfoo.dylib" }
831     ],
832     "exported_symbols": [
833       {
834         "data": {
835           "global": [ "_varFooBaz" ]
836         }
837       }
838     ]
839   }
840 ]})";
841 
842   InterfaceFile File;
843   File.setFileType(FileType::TBD_V5);
844 
845   TargetList AllTargets = {
846       Target(AK_armv7, PLATFORM_IOS, VersionTuple(11, 0)),
847       Target(AK_armv7s, PLATFORM_IOS, VersionTuple(11, 0)),
848   };
849   File.setInstallName("/S/L/F/Foo.framework/Foo");
850   File.addTarget(AllTargets[0]);
851   File.setCurrentVersion(PackedVersion(1, 0, 0));
852   File.setCompatibilityVersion(PackedVersion(1, 0, 0));
853   File.addReexportedLibrary("/u/l/l/libfoo.dylib", AllTargets[0]);
854   File.setTwoLevelNamespace();
855   File.setApplicationExtensionSafe(true);
856 
857   InterfaceFile NestedFile;
858   NestedFile.setFileType(FileType::TBD_V5);
859   NestedFile.setInstallName("/u/l/l/libfoo.dylib");
860   NestedFile.addTargets(AllTargets);
861   NestedFile.setCompatibilityVersion(PackedVersion(1, 0, 0));
862   NestedFile.setTwoLevelNamespace();
863   NestedFile.setApplicationExtensionSafe(false);
864   NestedFile.setCurrentVersion(PackedVersion(2, 1, 1));
865   NestedFile.addRPath(AllTargets[0], "@executable_path/.../Frameworks");
866   for (const auto &Targ : AllTargets)
867     NestedFile.addReexportedLibrary("@rpath/libfoo.dylib", Targ);
868   NestedFile.addSymbol(SymbolKind::GlobalSymbol, "_funcFoo", AllTargets,
869                        SymbolFlags::Text);
870   File.addDocument(std::make_shared<InterfaceFile>(std::move(NestedFile)));
871 
872   InterfaceFile NestedFileB;
873   NestedFileB.setFileType(FileType::TBD_V5);
874   NestedFileB.setInstallName("@rpath/libfoo.dylib");
875   NestedFileB.addTarget(AllTargets[0]);
876   NestedFileB.setCompatibilityVersion(PackedVersion(1, 0, 0));
877   NestedFileB.setCurrentVersion(PackedVersion(1, 0, 0));
878   NestedFileB.setTwoLevelNamespace();
879   NestedFileB.setApplicationExtensionSafe(true);
880   NestedFileB.addSymbol(SymbolKind::GlobalSymbol, "_varFooBaz", {AllTargets[0]},
881                         SymbolFlags::Data);
882   File.addDocument(std::make_shared<InterfaceFile>(std::move(NestedFileB)));
883 
884   // Write out file then process it back into IF and compare equality
885   // against TBDv5File.
886   SmallString<4096> Buffer;
887   raw_svector_ostream OS(Buffer);
888   Error Result = TextAPIWriter::writeToStream(OS, File, /*Compact=*/true);
889   EXPECT_FALSE(Result);
890 
891   Expected<TBDFile> Input =
892       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Input.tbd"));
893   EXPECT_TRUE(!!Input);
894   TBDFile InputFile = std::move(Input.get());
895 
896   Expected<TBDFile> Output =
897       TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
898   EXPECT_TRUE(!!Output);
899   TBDFile OutputFile = std::move(Output.get());
900   EXPECT_EQ(*InputFile, *OutputFile);
901 }
902 
903 TEST(TBDv5, Target_Simulator) {
904   static const char TBDv5File[] = R"({
905 "tapi_tbd_version": 5,
906 "main_library": {
907   "target_info": [
908     {
909       "target": "arm64-ios-simulator",
910       "min_deployment": "11.0"
911     },
912     {
913       "target": "x86_64-ios-simulator",
914       "min_deployment": "11.3"
915     }
916   ],
917   "install_names":[
918     { "name":"/S/L/F/Foo.framework/Foo" }
919   ]
920 }})";
921 
922   Expected<TBDFile> Result =
923       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
924   EXPECT_TRUE(!!Result);
925   TBDFile File = std::move(Result.get());
926   EXPECT_EQ(FileType::TBD_V5, File->getFileType());
927   TargetList ExpectedTargets = {
928       Target(AK_x86_64, PLATFORM_IOSSIMULATOR, VersionTuple(11, 3)),
929       Target(AK_arm64, PLATFORM_IOSSIMULATOR, VersionTuple(11, 0)),
930   };
931   TargetList Targets{File->targets().begin(), File->targets().end()};
932   llvm::sort(Targets);
933   EXPECT_EQ(Targets, ExpectedTargets);
934 
935   SmallString<4096> Buffer;
936   raw_svector_ostream OS(Buffer);
937   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
938   EXPECT_TRUE(!WriteResult);
939 
940   Expected<TBDFile> Output =
941       TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
942   EXPECT_TRUE(!!Output);
943   TBDFile WriteResultFile = std::move(Output.get());
944   EXPECT_EQ(*File, *WriteResultFile);
945 }
946 
947 TEST(TBDv5, Target_UnsupportedMinOS) {
948   static const char TBDv5File[] = R"({
949 "tapi_tbd_version": 5,
950 "main_library": {
951   "target_info": [
952     {
953       "target": "arm64-macos",
954       "min_deployment": "10.14"
955     },
956     {
957       "target": "x86_64-macos",
958       "min_deployment": "10.14"
959     }
960   ],
961   "install_names":[
962     { "name":"/S/L/F/Foo.framework/Foo" }
963   ]
964 }})";
965 
966   Expected<TBDFile> Result =
967       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
968   EXPECT_TRUE(!!Result);
969   TBDFile File = std::move(Result.get());
970   EXPECT_EQ(FileType::TBD_V5, File->getFileType());
971   TargetList ExpectedTargets = {
972       Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
973       Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0)),
974   };
975   TargetList Targets{File->targets().begin(), File->targets().end()};
976   llvm::sort(Targets);
977   EXPECT_EQ(Targets, ExpectedTargets);
978 
979   SmallString<4096> Buffer;
980   raw_svector_ostream OS(Buffer);
981   Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
982   EXPECT_TRUE(!WriteResult);
983 
984   Expected<TBDFile> Output =
985       TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
986   EXPECT_TRUE(!!Output);
987   TBDFile WriteResultFile = std::move(Output.get());
988   EXPECT_EQ(*File, *WriteResultFile);
989 }
990 
991 TEST(TBDv5, MisspelledKey) {
992   static const char TBDv5File[] = R"({
993 "tapi_tbd_version": 5,
994 "main_library": {
995   "target_info": [
996     {
997       "target": "arm64-ios-simulator",
998       "min_deployment": "11.0"
999     }
1000   ],
1001   "intall_names":[
1002     { "name":"/S/L/F/Foo.framework/Foo" }
1003   ]
1004 }})";
1005 
1006   Expected<TBDFile> Result =
1007       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
1008   EXPECT_FALSE(!!Result);
1009   std::string ErrorMessage = toString(Result.takeError());
1010   EXPECT_EQ("invalid install_names section\n", ErrorMessage);
1011 }
1012 
1013 TEST(TBDv5, InvalidVersion) {
1014   static const char TBDv5File[] = R"({
1015 "tapi_tbd_version": 11,
1016 "main_library": {
1017   "target_info": [
1018     {
1019       "target": "arm64-ios-simulator",
1020       "min_deployment": "11.0"
1021     }
1022   ],
1023   "install_names":[
1024     { "name":"/S/L/F/Foo.framework/Foo" }
1025   ]
1026 }})";
1027 
1028   Expected<TBDFile> Result =
1029       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
1030   EXPECT_FALSE(!!Result);
1031   std::string ErrorMessage = toString(Result.takeError());
1032   EXPECT_EQ("invalid tapi_tbd_version section\n", ErrorMessage);
1033 }
1034 
1035 TEST(TBDv5, MissingRequiredKey) {
1036   static const char TBDv5File[] = R"({
1037 "main_library": {
1038   "target_info": [
1039     {
1040       "target": "arm64-ios-simulator",
1041       "min_deployment": "11.0"
1042     }
1043   ],
1044   "install_names":[
1045     { "name":"/S/L/F/Foo.framework/Foo" }
1046   ]
1047 }})";
1048 
1049   Expected<TBDFile> Result =
1050       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
1051   EXPECT_FALSE(!!Result);
1052   std::string ErrorMessage = toString(Result.takeError());
1053   EXPECT_EQ("invalid tapi_tbd_version section\n", ErrorMessage);
1054 }
1055 
1056 TEST(TBDv5, InvalidSymbols) {
1057   static const char TBDv5File[] = R"({
1058 "tapi_tbd_version": 5,
1059 "main_library": {
1060   "target_info": [
1061     {
1062       "target": "arm64-driverkit",
1063       "min_deployment": "11.0"
1064     }
1065   ],
1066   "install_names":[
1067     { "name":"/S/L/F/Foo.framework/Foo" }
1068   ],
1069   "exported_symbols": [
1070     {
1071       "daa": {
1072         "global": {
1073             "weak": []
1074           }
1075       }
1076     }
1077   ]
1078 }})";
1079 
1080   Expected<TBDFile> Result =
1081       TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
1082   EXPECT_FALSE(!!Result);
1083   std::string ErrorMessage = toString(Result.takeError());
1084   EXPECT_EQ("invalid exported_symbols section\n", ErrorMessage);
1085 }
1086 
1087 } // end namespace TBDv5
1088