xref: /llvm-project/llvm/unittests/TextAPI/TextStubV5Tests.cpp (revision b2b50980de240b3d89e0f9340b51d6d6079fd19d)
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 } // end namespace TBDv5
524