TextStubV1Tests.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. //===-- TextStubV1Tests.cpp - TBD V1 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 "llvm/TextAPI/MachO/InterfaceFile.h"
  9. #include "llvm/TextAPI/MachO/TextAPIReader.h"
  10. #include "llvm/TextAPI/MachO/TextAPIWriter.h"
  11. #include "gtest/gtest.h"
  12. #include <string>
  13. #include <vector>
  14. using namespace llvm;
  15. using namespace llvm::MachO;
  16. struct ExportedSymbol {
  17. SymbolKind Kind;
  18. std::string Name;
  19. bool WeakDefined;
  20. bool ThreadLocalValue;
  21. };
  22. using ExportedSymbolSeq = std::vector<ExportedSymbol>;
  23. inline bool operator<(const ExportedSymbol &lhs, const ExportedSymbol &rhs) {
  24. return std::tie(lhs.Kind, lhs.Name) < std::tie(rhs.Kind, rhs.Name);
  25. }
  26. inline bool operator==(const ExportedSymbol &lhs, const ExportedSymbol &rhs) {
  27. return std::tie(lhs.Kind, lhs.Name, lhs.WeakDefined, lhs.ThreadLocalValue) ==
  28. std::tie(rhs.Kind, rhs.Name, rhs.WeakDefined, rhs.ThreadLocalValue);
  29. }
  30. static ExportedSymbol TBDv1Symbols[] = {
  31. {SymbolKind::GlobalSymbol, "$ld$hide$os9.0$_sym1", false, false},
  32. {SymbolKind::GlobalSymbol, "_sym1", false, false},
  33. {SymbolKind::GlobalSymbol, "_sym2", false, false},
  34. {SymbolKind::GlobalSymbol, "_sym3", false, false},
  35. {SymbolKind::GlobalSymbol, "_sym4", false, false},
  36. {SymbolKind::GlobalSymbol, "_sym5", false, false},
  37. {SymbolKind::GlobalSymbol, "_tlv1", false, true},
  38. {SymbolKind::GlobalSymbol, "_tlv2", false, true},
  39. {SymbolKind::GlobalSymbol, "_tlv3", false, true},
  40. {SymbolKind::GlobalSymbol, "_weak1", true, false},
  41. {SymbolKind::GlobalSymbol, "_weak2", true, false},
  42. {SymbolKind::GlobalSymbol, "_weak3", true, false},
  43. {SymbolKind::ObjectiveCClass, "class1", false, false},
  44. {SymbolKind::ObjectiveCClass, "class2", false, false},
  45. {SymbolKind::ObjectiveCClass, "class3", false, false},
  46. {SymbolKind::ObjectiveCInstanceVariable, "class1._ivar1", false, false},
  47. {SymbolKind::ObjectiveCInstanceVariable, "class1._ivar2", false, false},
  48. {SymbolKind::ObjectiveCInstanceVariable, "class1._ivar3", false, false},
  49. };
  50. namespace TBDv1 {
  51. TEST(TBDv1, ReadFile) {
  52. static const char tbd_v1_file1[] =
  53. "---\n"
  54. "archs: [ armv7, armv7s, armv7k, arm64 ]\n"
  55. "platform: ios\n"
  56. "install-name: Test.dylib\n"
  57. "current-version: 2.3.4\n"
  58. "compatibility-version: 1.0\n"
  59. "swift-version: 1.1\n"
  60. "exports:\n"
  61. " - archs: [ armv7, armv7s, armv7k, arm64 ]\n"
  62. " allowed-clients: [ clientA ]\n"
  63. " re-exports: [ /usr/lib/libfoo.dylib ]\n"
  64. " symbols: [ _sym1, _sym2, _sym3, _sym4, $ld$hide$os9.0$_sym1 ]\n"
  65. " objc-classes: [ _class1, _class2 ]\n"
  66. " objc-ivars: [ _class1._ivar1, _class1._ivar2 ]\n"
  67. " weak-def-symbols: [ _weak1, _weak2 ]\n"
  68. " thread-local-symbols: [ _tlv1, _tlv2 ]\n"
  69. " - archs: [ armv7, armv7s, armv7k ]\n"
  70. " symbols: [ _sym5 ]\n"
  71. " objc-classes: [ _class3 ]\n"
  72. " objc-ivars: [ _class1._ivar3 ]\n"
  73. " weak-def-symbols: [ _weak3 ]\n"
  74. " thread-local-symbols: [ _tlv3 ]\n"
  75. "...\n";
  76. auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_file1, "Test.tbd"));
  77. EXPECT_TRUE(!!Result);
  78. auto File = std::move(Result.get());
  79. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  80. auto Archs = AK_armv7 | AK_armv7s | AK_armv7k | AK_arm64;
  81. EXPECT_EQ(Archs, File->getArchitectures());
  82. EXPECT_EQ(PlatformKind::iOS, File->getPlatform());
  83. EXPECT_EQ(std::string("Test.dylib"), File->getInstallName());
  84. EXPECT_EQ(PackedVersion(2, 3, 4), File->getCurrentVersion());
  85. EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());
  86. EXPECT_EQ(2U, File->getSwiftABIVersion());
  87. EXPECT_EQ(ObjCConstraintType::None, File->getObjCConstraint());
  88. EXPECT_TRUE(File->isTwoLevelNamespace());
  89. EXPECT_TRUE(File->isApplicationExtensionSafe());
  90. EXPECT_FALSE(File->isInstallAPI());
  91. InterfaceFileRef client("clientA", Archs);
  92. InterfaceFileRef reexport("/usr/lib/libfoo.dylib", Archs);
  93. EXPECT_EQ(1U, File->allowableClients().size());
  94. EXPECT_EQ(client, File->allowableClients().front());
  95. EXPECT_EQ(1U, File->reexportedLibraries().size());
  96. EXPECT_EQ(reexport, File->reexportedLibraries().front());
  97. ExportedSymbolSeq Exports;
  98. for (const auto *Sym : File->symbols()) {
  99. EXPECT_FALSE(Sym->isWeakReferenced());
  100. EXPECT_FALSE(Sym->isUndefined());
  101. Exports.emplace_back(ExportedSymbol{Sym->getKind(), Sym->getName(),
  102. Sym->isWeakDefined(),
  103. Sym->isThreadLocalValue()});
  104. }
  105. llvm::sort(Exports.begin(), Exports.end());
  106. EXPECT_EQ(sizeof(TBDv1Symbols) / sizeof(ExportedSymbol), Exports.size());
  107. EXPECT_TRUE(
  108. std::equal(Exports.begin(), Exports.end(), std::begin(TBDv1Symbols)));
  109. }
  110. TEST(TBDv1, ReadFile2) {
  111. static const char tbd_v1_file2[] = "--- !tapi-tbd-v1\n"
  112. "archs: [ armv7, armv7s, armv7k, arm64 ]\n"
  113. "platform: ios\n"
  114. "install-name: Test.dylib\n"
  115. "...\n";
  116. auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_file2, "Test.tbd"));
  117. EXPECT_TRUE(!!Result);
  118. auto File = std::move(Result.get());
  119. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  120. auto Archs = AK_armv7 | AK_armv7s | AK_armv7k | AK_arm64;
  121. EXPECT_EQ(Archs, File->getArchitectures());
  122. EXPECT_EQ(PlatformKind::iOS, File->getPlatform());
  123. EXPECT_EQ(std::string("Test.dylib"), File->getInstallName());
  124. EXPECT_EQ(PackedVersion(1, 0, 0), File->getCurrentVersion());
  125. EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());
  126. EXPECT_EQ(0U, File->getSwiftABIVersion());
  127. EXPECT_EQ(ObjCConstraintType::None, File->getObjCConstraint());
  128. EXPECT_TRUE(File->isTwoLevelNamespace());
  129. EXPECT_TRUE(File->isApplicationExtensionSafe());
  130. EXPECT_FALSE(File->isInstallAPI());
  131. EXPECT_EQ(0U, File->allowableClients().size());
  132. EXPECT_EQ(0U, File->reexportedLibraries().size());
  133. }
  134. TEST(TBDv1, WriteFile) {
  135. static const char tbd_v1_file3[] =
  136. "---\n"
  137. "archs: [ i386, x86_64 ]\n"
  138. "platform: macosx\n"
  139. "install-name: '/usr/lib/libfoo.dylib'\n"
  140. "current-version: 1.2.3\n"
  141. "compatibility-version: 0\n"
  142. "swift-version: 5\n"
  143. "objc-constraint: retain_release\n"
  144. "exports:\n"
  145. " - archs: [ i386 ]\n"
  146. " symbols: [ _sym1 ]\n"
  147. " weak-def-symbols: [ _sym2 ]\n"
  148. " thread-local-symbols: [ _sym3 ]\n"
  149. " - archs: [ x86_64 ]\n"
  150. " allowed-clients: [ clientA ]\n"
  151. " re-exports: [ '/usr/lib/libfoo.dylib' ]\n"
  152. " symbols: [ '_OBJC_EHTYPE_$_Class1' ]\n"
  153. " objc-classes: [ _Class1 ]\n"
  154. " objc-ivars: [ _Class1._ivar1 ]\n"
  155. "...\n";
  156. InterfaceFile File;
  157. File.setPath("libfoo.dylib");
  158. File.setInstallName("/usr/lib/libfoo.dylib");
  159. File.setFileType(FileType::TBD_V1);
  160. File.setArchitectures(AK_i386 | AK_x86_64);
  161. File.setPlatform(PlatformKind::macOS);
  162. File.setCurrentVersion(PackedVersion(1, 2, 3));
  163. File.setSwiftABIVersion(5);
  164. File.setObjCConstraint(ObjCConstraintType::Retain_Release);
  165. File.addAllowableClient("clientA", AK_x86_64);
  166. File.addReexportedLibrary("/usr/lib/libfoo.dylib", AK_x86_64);
  167. File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", AK_i386);
  168. File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", AK_i386,
  169. SymbolFlags::WeakDefined);
  170. File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", AK_i386,
  171. SymbolFlags::ThreadLocalValue);
  172. File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", AK_x86_64);
  173. File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", AK_x86_64);
  174. File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1",
  175. AK_x86_64);
  176. SmallString<4096> Buffer;
  177. raw_svector_ostream OS(Buffer);
  178. auto Result = TextAPIWriter::writeToStream(OS, File);
  179. EXPECT_FALSE(Result);
  180. EXPECT_STREQ(tbd_v1_file3, Buffer.c_str());
  181. }
  182. TEST(TBDv1, Platform_macOS) {
  183. static const char tbd_v1_platform_macos[] = "---\n"
  184. "archs: [ x86_64 ]\n"
  185. "platform: macosx\n"
  186. "install-name: Test.dylib\n"
  187. "...\n";
  188. auto Result =
  189. TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_macos, "Test.tbd"));
  190. EXPECT_TRUE(!!Result);
  191. auto File = std::move(Result.get());
  192. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  193. EXPECT_EQ(PlatformKind::macOS, File->getPlatform());
  194. }
  195. TEST(TBDv1, Platform_iOS) {
  196. static const char tbd_v1_platform_ios[] = "---\n"
  197. "archs: [ arm64 ]\n"
  198. "platform: ios\n"
  199. "install-name: Test.dylib\n"
  200. "...\n";
  201. auto Result =
  202. TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_ios, "Test.tbd"));
  203. EXPECT_TRUE(!!Result);
  204. auto File = std::move(Result.get());
  205. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  206. EXPECT_EQ(PlatformKind::iOS, File->getPlatform());
  207. }
  208. TEST(TBDv1, Platform_watchOS) {
  209. static const char tbd_v1_platform_watchos[] = "---\n"
  210. "archs: [ armv7k ]\n"
  211. "platform: watchos\n"
  212. "install-name: Test.dylib\n"
  213. "...\n";
  214. auto Result =
  215. TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_watchos, "Test.tbd"));
  216. EXPECT_TRUE(!!Result);
  217. auto File = std::move(Result.get());
  218. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  219. EXPECT_EQ(PlatformKind::watchOS, File->getPlatform());
  220. }
  221. TEST(TBDv1, Platform_tvOS) {
  222. static const char tbd_v1_platform_tvos[] = "---\n"
  223. "archs: [ arm64 ]\n"
  224. "platform: tvos\n"
  225. "install-name: Test.dylib\n"
  226. "...\n";
  227. auto Result =
  228. TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_tvos, "Test.tbd"));
  229. EXPECT_TRUE(!!Result);
  230. auto File = std::move(Result.get());
  231. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  232. EXPECT_EQ(PlatformKind::tvOS, File->getPlatform());
  233. }
  234. TEST(TBDv1, Platform_bridgeOS) {
  235. static const char tbd_v1_platform_bridgeos[] = "---\n"
  236. "archs: [ armv7k ]\n"
  237. "platform: bridgeos\n"
  238. "install-name: Test.dylib\n"
  239. "...\n";
  240. auto Result =
  241. TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_bridgeos, "Test.tbd"));
  242. EXPECT_TRUE(!!Result);
  243. auto File = std::move(Result.get());
  244. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  245. EXPECT_EQ(PlatformKind::bridgeOS, File->getPlatform());
  246. }
  247. TEST(TBDv1, Swift_1_0) {
  248. static const char tbd_v1_swift_1_0[] = "---\n"
  249. "archs: [ arm64 ]\n"
  250. "platform: ios\n"
  251. "install-name: Test.dylib\n"
  252. "swift-version: 1.0\n"
  253. "...\n";
  254. auto Result =
  255. TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_1_0, "Test.tbd"));
  256. EXPECT_TRUE(!!Result);
  257. auto File = std::move(Result.get());
  258. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  259. EXPECT_EQ(1U, File->getSwiftABIVersion());
  260. }
  261. TEST(TBDv1, Swift_1_1) {
  262. static const char tbd_v1_swift_1_1[] = "---\n"
  263. "archs: [ arm64 ]\n"
  264. "platform: ios\n"
  265. "install-name: Test.dylib\n"
  266. "swift-version: 1.1\n"
  267. "...\n";
  268. auto Result =
  269. TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_1_1, "Test.tbd"));
  270. EXPECT_TRUE(!!Result);
  271. auto File = std::move(Result.get());
  272. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  273. EXPECT_EQ(2U, File->getSwiftABIVersion());
  274. }
  275. TEST(TBDv1, Swift_2_0) {
  276. static const char tbd_v1_swift_2_0[] = "---\n"
  277. "archs: [ arm64 ]\n"
  278. "platform: ios\n"
  279. "install-name: Test.dylib\n"
  280. "swift-version: 2.0\n"
  281. "...\n";
  282. auto Result =
  283. TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_2_0, "Test.tbd"));
  284. EXPECT_TRUE(!!Result);
  285. auto File = std::move(Result.get());
  286. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  287. EXPECT_EQ(3U, File->getSwiftABIVersion());
  288. }
  289. TEST(TBDv1, Swift_3_0) {
  290. static const char tbd_v1_swift_3_0[] = "---\n"
  291. "archs: [ arm64 ]\n"
  292. "platform: ios\n"
  293. "install-name: Test.dylib\n"
  294. "swift-version: 3.0\n"
  295. "...\n";
  296. auto Result =
  297. TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_3_0, "Test.tbd"));
  298. EXPECT_TRUE(!!Result);
  299. auto File = std::move(Result.get());
  300. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  301. EXPECT_EQ(4U, File->getSwiftABIVersion());
  302. }
  303. TEST(TBDv1, Swift_4_0) {
  304. static const char tbd_v1_swift_4_0[] = "---\n"
  305. "archs: [ arm64 ]\n"
  306. "platform: ios\n"
  307. "install-name: Test.dylib\n"
  308. "swift-version: 4.0\n"
  309. "...\n";
  310. auto Result =
  311. TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_4_0, "Test.tbd"));
  312. EXPECT_FALSE(!!Result);
  313. auto errorMessage = toString(Result.takeError());
  314. EXPECT_EQ("malformed file\nTest.tbd:5:16: error: invalid Swift ABI "
  315. "version.\nswift-version: 4.0\n ^~~\n",
  316. errorMessage);
  317. }
  318. TEST(TBDv1, Swift_5) {
  319. static const char tbd_v1_swift_5[] = "---\n"
  320. "archs: [ arm64 ]\n"
  321. "platform: ios\n"
  322. "install-name: Test.dylib\n"
  323. "swift-version: 5\n"
  324. "...\n";
  325. auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_5, "Test.tbd"));
  326. EXPECT_TRUE(!!Result);
  327. auto File = std::move(Result.get());
  328. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  329. EXPECT_EQ(5U, File->getSwiftABIVersion());
  330. }
  331. TEST(TBDv1, Swift_99) {
  332. static const char tbd_v1_swift_99[] = "---\n"
  333. "archs: [ arm64 ]\n"
  334. "platform: ios\n"
  335. "install-name: Test.dylib\n"
  336. "swift-version: 99\n"
  337. "...\n";
  338. auto Result =
  339. TextAPIReader::get(MemoryBufferRef(tbd_v1_swift_99, "Test.tbd"));
  340. EXPECT_TRUE(!!Result);
  341. auto File = std::move(Result.get());
  342. EXPECT_EQ(FileType::TBD_V1, File->getFileType());
  343. EXPECT_EQ(99U, File->getSwiftABIVersion());
  344. }
  345. TEST(TBDv1, UnknownArchitecture) {
  346. static const char tbd_v1_file_unknown_architecture[] =
  347. "---\n"
  348. "archs: [ foo ]\n"
  349. "platform: macosx\n"
  350. "install-name: Test.dylib\n"
  351. "...\n";
  352. auto Result = TextAPIReader::get(
  353. MemoryBufferRef(tbd_v1_file_unknown_architecture, "Test.tbd"));
  354. EXPECT_TRUE(!!Result);
  355. }
  356. TEST(TBDv1, UnknownPlatform) {
  357. static const char tbd_v1_file_unknown_platform[] = "---\n"
  358. "archs: [ i386 ]\n"
  359. "platform: newOS\n"
  360. "...\n";
  361. auto Result = TextAPIReader::get(
  362. MemoryBufferRef(tbd_v1_file_unknown_platform, "Test.tbd"));
  363. EXPECT_FALSE(!!Result);
  364. auto errorMessage = toString(Result.takeError());
  365. EXPECT_EQ("malformed file\nTest.tbd:3:11: error: unknown platform\nplatform: "
  366. "newOS\n ^~~~~\n",
  367. errorMessage);
  368. }
  369. TEST(TBDv1, MalformedFile1) {
  370. static const char malformed_file1[] = "---\n"
  371. "archs: [ arm64 ]\n"
  372. "foobar: \"Unsupported key\"\n"
  373. "...\n";
  374. auto Result =
  375. TextAPIReader::get(MemoryBufferRef(malformed_file1, "Test.tbd"));
  376. EXPECT_FALSE(!!Result);
  377. auto errorMessage = toString(Result.takeError());
  378. ASSERT_EQ("malformed file\nTest.tbd:2:1: error: missing required key "
  379. "'platform'\narchs: [ arm64 ]\n^\n",
  380. errorMessage);
  381. }
  382. TEST(TBDv1, MalformedFile2) {
  383. static const char malformed_file2[] = "---\n"
  384. "archs: [ arm64 ]\n"
  385. "platform: ios\n"
  386. "install-name: Test.dylib\n"
  387. "foobar: \"Unsupported key\"\n"
  388. "...\n";
  389. auto Result =
  390. TextAPIReader::get(MemoryBufferRef(malformed_file2, "Test.tbd"));
  391. EXPECT_FALSE(!!Result);
  392. auto errorMessage = toString(Result.takeError());
  393. ASSERT_EQ(
  394. "malformed file\nTest.tbd:5:9: error: unknown key 'foobar'\nfoobar: "
  395. "\"Unsupported key\"\n ^~~~~~~~~~~~~~~~~\n",
  396. errorMessage);
  397. }
  398. } // end namespace TBDv1.