//===- NativeDylibManagerTest.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Test NativeDylibManager APIs. // //===----------------------------------------------------------------------===// #include "orc-rt/NativeDylibManager.h" #include "orc-rt/Session.h" #include "gtest/gtest.h" #include "CommonTestUtils.h" #include using namespace orc_rt; namespace { // Local aliases for brevity in test bodies. constexpr auto Req = NativeDylibManager::RequiredSymbol; constexpr auto Weak = NativeDylibManager::WeaklyReferencedSymbol; } // namespace #ifndef NDM_TEST_LIB_PATH #error \ "NDM_TEST_LIB_PATH must be defined to the path of the test shared library" #endif // Helper: synchronously run load and return result. static Expected syncLoad(NativeDylibManager &NDM, std::string Path) { std::optional> Result; NDM.load([&](Expected R) { Result = std::move(R); }, std::move(Path)); return std::move(*Result); } // Helper: synchronously run lookup and return results. static Expected> syncLookup(NativeDylibManager &NDM, void *Handle, NativeDylibManager::SymbolLookupSet Symbols) { std::optional>> Result; NDM.lookup([&](Expected> R) { Result = std::move(R); }, Handle, std::move(Symbols)); return std::move(*Result); } TEST(NativeDylibManagerTest, Create) { Session S(mockExecutorProcessInfo(), std::make_unique(), noErrors); SimpleSymbolTable ST; auto NDM = NativeDylibManager::Create(S, ST); ASSERT_TRUE(!!NDM) << toString(NDM.takeError()); } TEST(NativeDylibManagerTest, Load) { Session S(mockExecutorProcessInfo(), std::make_unique(), noErrors); SimpleSymbolTable ST; auto NDM = cantFail(NativeDylibManager::Create(S, ST)); auto LoadResult = syncLoad(*NDM, NDM_TEST_LIB_PATH); ASSERT_TRUE(!!LoadResult) << toString(LoadResult.takeError()); EXPECT_NE(*LoadResult, nullptr); } TEST(NativeDylibManagerTest, LoadNonExistent) { Session S(mockExecutorProcessInfo(), std::make_unique(), noErrors); SimpleSymbolTable ST; auto NDM = cantFail(NativeDylibManager::Create(S, ST)); auto LoadResult = syncLoad(*NDM, "/no/such/library.dylib"); EXPECT_FALSE(!!LoadResult); consumeError(LoadResult.takeError()); } TEST(NativeDylibManagerTest, LookupSingleSymbol) { Session S(mockExecutorProcessInfo(), std::make_unique(), noErrors); SimpleSymbolTable ST; auto NDM = cantFail(NativeDylibManager::Create(S, ST)); void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH)); auto Result = syncLookup(*NDM, Handle, {{"NativeDylibManagerTestFunc", Req}}); ASSERT_TRUE(!!Result) << toString(Result.takeError()); ASSERT_EQ(Result->size(), 1U); EXPECT_NE((*Result)[0], nullptr); // Verify the symbol points to the right function. auto *Func = reinterpret_cast((*Result)[0]); EXPECT_EQ(Func(), 42); } TEST(NativeDylibManagerTest, LookupMultipleSymbols) { Session S(mockExecutorProcessInfo(), std::make_unique(), noErrors); SimpleSymbolTable ST; auto NDM = cantFail(NativeDylibManager::Create(S, ST)); void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH)); auto Result = syncLookup(*NDM, Handle, {{"NativeDylibManagerTestFunc", Req}, {"NativeDylibManagerTestFunc2", Req}}); ASSERT_TRUE(!!Result) << toString(Result.takeError()); ASSERT_EQ(Result->size(), 2U); EXPECT_NE((*Result)[0], nullptr); EXPECT_NE((*Result)[1], nullptr); auto *Func1 = reinterpret_cast((*Result)[0]); auto *Func2 = reinterpret_cast((*Result)[1]); EXPECT_EQ(Func1(), 42); EXPECT_EQ(Func2(), 7); } TEST(NativeDylibManagerTest, LookupWeakMissingSymbol) { Session S(mockExecutorProcessInfo(), std::make_unique(), noErrors); SimpleSymbolTable ST; auto NDM = cantFail(NativeDylibManager::Create(S, ST)); void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH)); auto Result = syncLookup(*NDM, Handle, {{"no_such_symbol", Weak}}); ASSERT_TRUE(!!Result) << toString(Result.takeError()); ASSERT_EQ(Result->size(), 1U); EXPECT_EQ((*Result)[0], nullptr); } TEST(NativeDylibManagerTest, LookupRequiredMissingSymbol) { Session S(mockExecutorProcessInfo(), std::make_unique(), noErrors); SimpleSymbolTable ST; auto NDM = cantFail(NativeDylibManager::Create(S, ST)); void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH)); auto Result = syncLookup(*NDM, Handle, {{"no_such_symbol", Req}}); EXPECT_FALSE(!!Result); auto Msg = toString(Result.takeError()); EXPECT_NE(Msg.find("no_such_symbol"), std::string::npos) << "error message should mention the missing symbol; got: " << Msg; } TEST(NativeDylibManagerTest, LookupMixedRequiredAndWeak) { Session S(mockExecutorProcessInfo(), std::make_unique(), noErrors); SimpleSymbolTable ST; auto NDM = cantFail(NativeDylibManager::Create(S, ST)); void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH)); auto Result = syncLookup( *NDM, Handle, {{"NativeDylibManagerTestFunc", Req}, {"no_such_symbol", Weak}}); ASSERT_TRUE(!!Result) << toString(Result.takeError()); ASSERT_EQ(Result->size(), 2U); EXPECT_NE((*Result)[0], nullptr); EXPECT_EQ((*Result)[1], nullptr); }