Skip to content

Commit dfaf4f3

Browse files
Add test to run things in parallel
1 parent 271c592 commit dfaf4f3

File tree

9 files changed

+173
-21
lines changed

9 files changed

+173
-21
lines changed

lib/CppInterOp/CppInterOp.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3459,6 +3459,8 @@ static inline auto find_interpreter_in_map(InterpreterInfo* I) {
34593459
bool DeleteInterpreter(TInterp_t I /*=nullptr*/) {
34603460
std::lock_guard<std::recursive_mutex> Lock(InterpreterStackLock);
34613461
assert(sInterpreters->size() == sInterpreterASTMap->size());
3462+
if (sInterpreters->empty())
3463+
return false;
34623464

34633465
if (!I) {
34643466
auto foundAST = find_interpreter_in_map(sInterpreters->back().get());

unittests/CppInterOp/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ set_output_directory(DynamicLibraryManagerTests
128128
)
129129

130130
add_dependencies(DynamicLibraryManagerTests TestSharedLib)
131+
add_dependencies(DynamicLibraryManagerTests TestSharedLib2)
131132

132133
#export_executable_symbols_for_plugins(TestSharedLib)
133134
add_subdirectory(TestSharedLib)
135+
add_subdirectory(TestSharedLib2)

unittests/CppInterOp/DynamicLibraryManagerTest.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ std::string GetExecutablePath(const char* Argv0) {
1919
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
2020
}
2121

22-
TEST(DynamicLibraryManagerTest, Sanity) {
22+
TEST(DynamicLibraryManagerTest, Sanity1) {
2323
#ifdef EMSCRIPTEN
2424
GTEST_SKIP() << "Test fails for Emscipten builds";
2525
#endif
@@ -66,6 +66,55 @@ TEST(DynamicLibraryManagerTest, Sanity) {
6666
// EXPECT_FALSE(Cpp::GetFunctionAddress("ret_zero"));
6767
}
6868

69+
TEST(DynamicLibraryManagerTest, Sanity2) {
70+
#ifdef EMSCRIPTEN
71+
GTEST_SKIP() << "Test fails for Emscipten builds";
72+
#endif
73+
74+
#if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \
75+
defined(_WIN32)
76+
GTEST_SKIP() << "Test fails with Cling on Windows";
77+
#endif
78+
79+
auto* I = Cpp::CreateInterpreter();
80+
EXPECT_TRUE(I);
81+
EXPECT_FALSE(Cpp::GetFunctionAddress("ret_one", I));
82+
83+
std::string BinaryPath = GetExecutablePath(/*Argv0=*/nullptr);
84+
llvm::StringRef Dir = llvm::sys::path::parent_path(BinaryPath);
85+
Cpp::AddSearchPath(Dir.str().c_str(), true, false, I);
86+
87+
// FIXME: dlsym on mach-o takes the C-level name, however, the macho-o format
88+
// adds an additional underscore (_) prefix to the lowered names. Figure out
89+
// how to harmonize that API.
90+
#ifdef __APPLE__
91+
std::string PathToTestSharedLib =
92+
Cpp::SearchLibrariesForSymbol("_ret_one", /*system_search=*/false, I);
93+
#else
94+
std::string PathToTestSharedLib =
95+
Cpp::SearchLibrariesForSymbol("ret_one", /*system_search=*/false, I);
96+
#endif // __APPLE__
97+
98+
EXPECT_STRNE("", PathToTestSharedLib.c_str())
99+
<< "Cannot find: '" << PathToTestSharedLib << "' in '" << Dir.str()
100+
<< "'";
101+
102+
EXPECT_TRUE(Cpp::LoadLibrary(PathToTestSharedLib.c_str(), true, I));
103+
// Force ExecutionEngine to be created.
104+
Cpp::Process("", I);
105+
Cpp::Declare("", I);
106+
// FIXME: Conda returns false to run this code on osx.
107+
#ifndef __APPLE__
108+
EXPECT_TRUE(Cpp::GetFunctionAddress("ret_one", I));
109+
#endif //__APPLE__
110+
111+
Cpp::UnloadLibrary("TestSharedLib2", I);
112+
// We have no reliable way to check if it was unloaded because posix does not
113+
// require the library to be actually unloaded but just the handle to be
114+
// invalidated...
115+
// EXPECT_FALSE(Cpp::GetFunctionAddress("ret_zero"));
116+
}
117+
69118
TEST(DynamicLibraryManagerTest, BasicSymbolLookup) {
70119
#ifndef EMSCRIPTEN
71120
GTEST_SKIP() << "This test is only intended for Emscripten builds.";

unittests/CppInterOp/FunctionReflectionTest.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,8 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch1) {
10141014
GetAllTopLevelDecls(code, Decls);
10151015
std::vector<Cpp::TCppFunction_t> candidates;
10161016

1017+
EXPECT_FALSE(Cpp::BestOverloadFunctionMatch({}, {}, {}));
1018+
10171019
for (auto decl : Decls)
10181020
if (Cpp::IsTemplatedFunction(decl)) candidates.push_back((Cpp::TCppFunction_t)decl);
10191021

unittests/CppInterOp/InterpreterTest.cpp

Lines changed: 78 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
#include "clang-c/CXCppInterOp.h"
1818

1919
#include "llvm/ADT/SmallString.h"
20+
#include "llvm/Support/FileSystem.h"
2021
#include "llvm/Support/Path.h"
21-
#include <llvm/Support/FileSystem.h>
22+
#include "llvm/Support/raw_ostream.h"
2223

2324
#include <gmock/gmock.h>
2425
#include "gtest/gtest.h"
2526

2627
#include <algorithm>
28+
#include <cstdint>
29+
#include <thread>
2730
#include <utility>
2831

2932
using ::testing::StartsWith;
@@ -247,7 +250,7 @@ TEST(InterpreterTest, DISABLED_DetectResourceDir) {
247250
#ifdef _WIN32
248251
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";
249252
#endif
250-
Cpp::CreateInterpreter();
253+
auto* I = Cpp::CreateInterpreter();
251254
EXPECT_STRNE(Cpp::DetectResourceDir().c_str(), Cpp::GetResourceDir());
252255
llvm::SmallString<256> Clang(LLVM_BINARY_DIR);
253256
llvm::sys::path::append(Clang, "bin", "clang");
@@ -256,7 +259,7 @@ TEST(InterpreterTest, DISABLED_DetectResourceDir) {
256259
GTEST_SKIP() << "Test not run (Clang binary does not exist)";
257260

258261
std::string DetectedPath = Cpp::DetectResourceDir(Clang.str().str().c_str());
259-
EXPECT_STREQ(DetectedPath.c_str(), Cpp::GetResourceDir());
262+
EXPECT_STREQ(DetectedPath.c_str(), Cpp::GetResourceDir(I));
260263
}
261264

262265
TEST(InterpreterTest, DetectSystemCompilerIncludePaths) {
@@ -364,26 +367,81 @@ if (llvm::sys::RunningOnValgrind())
364367
#endif
365368
}
366369

370+
static int printf_jit(const char* format, ...) {
371+
llvm::errs() << "printf_jit called!\n";
372+
return 0;
373+
}
374+
367375
TEST(InterpreterTest, MultipleInterpreter) {
368-
#if CLANG_VERSION_MAJOR < 20 && defined(EMSCRIPTEN)
369-
GTEST_SKIP() << "Test fails for Emscipten LLVM 20 builds";
376+
#ifdef EMSCRIPTEN
377+
GTEST_SKIP() << "Test fails for Emscipten builds";
370378
#endif
371-
auto* I = Cpp::CreateInterpreter();
372-
EXPECT_TRUE(I);
373-
Cpp::Declare(R"(
374-
void f() {}
375-
)");
376-
Cpp::TCppScope_t f = Cpp::GetNamed("f");
379+
#ifdef _WIN32
380+
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";
381+
#endif
382+
// delete all old interpreters
383+
while (Cpp::DeleteInterpreter())
384+
;
385+
auto* I1 = Cpp::CreateInterpreter();
386+
EXPECT_TRUE(I1);
387+
388+
auto F = [](Cpp::TInterp_t I) {
389+
bool hasError = true;
390+
EXPECT_TRUE(Cpp::Evaluate("__cplusplus", &hasError, I) == 201402);
391+
EXPECT_FALSE(hasError);
392+
393+
Cpp::Declare(R"(
394+
extern "C" int printf(const char*,...);
395+
class MyKlass {};
396+
)",
397+
false, I);
398+
Cpp::TCppScope_t f = Cpp::GetNamed("printf", Cpp::GetGlobalScope(I));
399+
EXPECT_TRUE(f);
400+
EXPECT_TRUE(Cpp::GetComplexType(Cpp::GetType("int", I)));
401+
Cpp::TCppType_t MyKlass = Cpp::GetType("MyKlass", I);
402+
EXPECT_EQ(Cpp::GetTypeAsString(MyKlass), "MyKlass");
403+
EXPECT_EQ(Cpp::GetNumBases(MyKlass), 0);
404+
EXPECT_FALSE(Cpp::GetBaseClass(MyKlass, 3));
405+
std::vector<Cpp::TCppScope_t> members;
406+
Cpp::GetEnumConstantDatamembers(Cpp::GetScopeFromType(MyKlass), members);
407+
EXPECT_EQ(members.size(), 0);
408+
409+
EXPECT_FALSE(
410+
Cpp::InsertOrReplaceJitSymbol("printf", (uint64_t)&printf_jit, I));
411+
412+
auto f_callable = Cpp::MakeFunctionCallable(f);
413+
EXPECT_EQ(f_callable.getKind(), Cpp::JitCall::Kind::kGenericCall);
414+
415+
EXPECT_FALSE(
416+
Cpp::TakeInterpreter((TInterp_t)1)); // try to take ownership of an
417+
// interpreter that does not exist
418+
419+
std::vector<std::string> includes;
420+
Cpp::AddIncludePath("/non/existent/", I);
421+
Cpp::GetIncludePaths(includes, false, false, I);
422+
EXPECT_NE(std::find(includes.begin(), includes.end(), "/non/existent/"),
423+
std::end(includes));
424+
425+
EXPECT_TRUE(Cpp::InsertOrReplaceJitSymbol("non_existent", (uint64_t)&f, I));
426+
};
427+
F(I1);
377428

378429
auto* I2 = Cpp::CreateInterpreter();
430+
auto* I3 = Cpp::CreateInterpreter();
431+
auto* I4 = Cpp::CreateInterpreter();
379432
EXPECT_TRUE(I2);
380-
Cpp::Declare(R"(
381-
void ff() {}
382-
)");
383-
Cpp::TCppScope_t ff = Cpp::GetNamed("ff");
384-
385-
auto f_callable = Cpp::MakeFunctionCallable(f);
386-
EXPECT_EQ(f_callable.getKind(), Cpp::JitCall::Kind::kGenericCall);
387-
auto ff_callable = Cpp::MakeFunctionCallable(ff);
388-
EXPECT_EQ(ff_callable.getKind(), Cpp::JitCall::Kind::kGenericCall);
433+
EXPECT_TRUE(I3);
434+
EXPECT_TRUE(I4);
435+
436+
std::thread t2(F, I2);
437+
std::thread t3(F, I3);
438+
std::thread t4(F, I4);
439+
t2.join();
440+
t3.join();
441+
t4.join();
442+
443+
testing::internal::CaptureStderr();
444+
Cpp::Process("printf(\"Blah\");", I2);
445+
std::string cerrs = testing::internal::GetCapturedStderr();
446+
EXPECT_STREQ(cerrs.c_str(), "printf_jit called!\n");
389447
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
add_llvm_library(TestSharedLib2
2+
SHARED
3+
DISABLE_LLVM_LINK_LLVM_DYLIB
4+
BUILDTREE_ONLY
5+
TestSharedLib.cpp)
6+
# Put TestSharedLib2 next to the unit test executable.
7+
set_output_directory(TestSharedLib2
8+
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../TestSharedLib/unittests/bin/$<CONFIG>/
9+
LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/../TestSharedLib/unittests/bin/$<CONFIG>/
10+
)
11+
12+
13+
if (EMSCRIPTEN)
14+
set_target_properties(TestSharedLib2
15+
PROPERTIES NO_SONAME 1
16+
)
17+
target_link_options(TestSharedLib2
18+
PRIVATE "SHELL: -s WASM_BIGINT"
19+
PRIVATE "SHELL: -s SIDE_MODULE=1"
20+
)
21+
endif()
22+
23+
set_target_properties(TestSharedLib2 PROPERTIES FOLDER "Tests")
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include "TestSharedLib.h"
2+
3+
int ret_one() { return 1; }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#ifndef UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB2_H
2+
#define UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB2_H
3+
4+
// Avoid having to mangle/demangle the symbol name in tests
5+
#ifdef _WIN32
6+
extern "C" __declspec(dllexport) int ret_one();
7+
#else
8+
extern "C" int __attribute__((visibility("default"))) ret_one();
9+
#endif
10+
11+
#endif // UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB2_H

unittests/CppInterOp/VariableReflectionTest.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ TEST(VariableReflectionTest, GetVariableOffset) {
287287
std::vector<Cpp::TCppScope_t> datamembers;
288288
Cpp::GetDatamembers(Decls[4], datamembers);
289289

290+
EXPECT_FALSE((bool)Cpp::GetVariableOffset(nullptr));
291+
290292
EXPECT_TRUE((bool) Cpp::GetVariableOffset(Decls[0])); // a
291293
EXPECT_TRUE((bool) Cpp::GetVariableOffset(Decls[1])); // N
292294
EXPECT_TRUE((bool)Cpp::GetVariableOffset(Decls[2])); // S

0 commit comments

Comments
 (0)