Skip to content

Commit a420064

Browse files
committed
[test] ConstructArray, DestructArray, Allocate and Deallocate
1 parent fd78ba3 commit a420064

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

unittests/CppInterOp/FunctionReflectionTest.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,6 +2050,58 @@ TEST(FunctionReflectionTest, ConstructNested) {
20502050
output.clear();
20512051
}
20522052

2053+
TEST(FunctionReflectionTest, ConstructArray) {
2054+
#if defined(EMSCRIPTEN) && (CLANG_VERSION_MAJOR < 20)
2055+
GTEST_SKIP() << "Test fails for LLVM < 20 Emscripten builds";
2056+
#endif
2057+
if (llvm::sys::RunningOnValgrind())
2058+
GTEST_SKIP() << "XFAIL due to Valgrind report";
2059+
#ifdef _WIN32
2060+
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";
2061+
#endif
2062+
2063+
Cpp::CreateInterpreter();
2064+
2065+
Interp->declare(R"(
2066+
#include <new>
2067+
extern "C" int printf(const char*,...);
2068+
class C {
2069+
int x;
2070+
C() {
2071+
x = 42;
2072+
printf("\nConstructor Executed\n");
2073+
}
2074+
};
2075+
)");
2076+
2077+
Cpp::TCppScope_t scope = Cpp::GetNamed("C");
2078+
std::string output;
2079+
2080+
size_t a = 5; // Construct an array of 5 objects
2081+
void* where = Cpp::Allocate(scope, a); // operator new
2082+
2083+
testing::internal::CaptureStdout();
2084+
EXPECT_TRUE(where == Cpp::Construct(scope, where, a)); // placement new
2085+
// Check for the value of x which should be at the start of the object.
2086+
EXPECT_TRUE(*(int*)where == 42);
2087+
// Check for the value of x in the second object
2088+
int* obj = reinterpret_cast<int*>(reinterpret_cast<char*>(where) +
2089+
Cpp::SizeOf(scope));
2090+
EXPECT_TRUE(*obj == 42);
2091+
2092+
// Check for the value of x in the last object
2093+
obj = reinterpret_cast<int*>(reinterpret_cast<char*>(where) +
2094+
(Cpp::SizeOf(scope) * 4));
2095+
EXPECT_TRUE(*obj == 42);
2096+
Cpp::Destruct(where, scope, /*withFree=*/false, 5);
2097+
Cpp::Deallocate(scope, where, 5);
2098+
output = testing::internal::GetCapturedStdout();
2099+
EXPECT_EQ(output,
2100+
"\nConstructor Executed\n\nConstructor Executed\n\nConstructor "
2101+
"Executed\n\nConstructor Executed\n\nConstructor Executed\n");
2102+
output.clear();
2103+
}
2104+
20532105
TEST(FunctionReflectionTest, Destruct) {
20542106
#ifdef EMSCRIPTEN
20552107
GTEST_SKIP() << "Test fails for Emscipten builds";
@@ -2107,6 +2159,82 @@ TEST(FunctionReflectionTest, Destruct) {
21072159
clang_Interpreter_dispose(I);
21082160
}
21092161

2162+
TEST(FunctionReflectionTest, DestructArray) {
2163+
#ifdef EMSCRIPTEN
2164+
GTEST_SKIP() << "Test fails for Emscipten builds";
2165+
#endif
2166+
if (llvm::sys::RunningOnValgrind())
2167+
GTEST_SKIP() << "XFAIL due to Valgrind report";
2168+
2169+
#ifdef _WIN32
2170+
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";
2171+
#endif
2172+
2173+
std::vector<const char*> interpreter_args = {"-include", "new"};
2174+
Cpp::CreateInterpreter(interpreter_args);
2175+
2176+
Interp->declare(R"(
2177+
#include <new>
2178+
extern "C" int printf(const char*,...);
2179+
class C {
2180+
int x;
2181+
C() {
2182+
printf("\nCtor Executed\n");
2183+
x = 42;
2184+
}
2185+
~C() {
2186+
printf("\nDestructor Executed\n");
2187+
}
2188+
};
2189+
)");
2190+
2191+
Cpp::TCppScope_t scope = Cpp::GetNamed("C");
2192+
std::string output;
2193+
2194+
size_t a = 5; // Construct an array of 5 objects
2195+
void* where = Cpp::Allocate(scope, a); // operator new
2196+
EXPECT_TRUE(where == Cpp::Construct(scope, where, a)); // placement new
2197+
2198+
// verify the array of objects has been constructed
2199+
int* obj = reinterpret_cast<int*>(reinterpret_cast<char*>(where) +
2200+
Cpp::SizeOf(scope) * 4);
2201+
EXPECT_TRUE(*obj == 42);
2202+
2203+
testing::internal::CaptureStdout();
2204+
// destruct 3 out of 5 objects
2205+
Cpp::Destruct(where, scope, false, 3);
2206+
output = testing::internal::GetCapturedStdout();
2207+
2208+
EXPECT_EQ(
2209+
output,
2210+
"\nDestructor Executed\n\nDestructor Executed\n\nDestructor Executed\n");
2211+
output.clear();
2212+
testing::internal::CaptureStdout();
2213+
2214+
// destruct the rest
2215+
auto *new_head = reinterpret_cast<void*>(reinterpret_cast<char*>(where) +
2216+
(Cpp::SizeOf(scope) * 3));
2217+
Cpp::Destruct(new_head, scope, false, 2);
2218+
2219+
output = testing::internal::GetCapturedStdout();
2220+
EXPECT_EQ(output, "\nDestructor Executed\n\nDestructor Executed\n");
2221+
output.clear();
2222+
2223+
// deallocate since we call the destructor withFree = false
2224+
Cpp::Deallocate(scope, where, 5);
2225+
2226+
// perform the same withFree=true
2227+
where = Cpp::Allocate(scope, a);
2228+
EXPECT_TRUE(where == Cpp::Construct(scope, where, a));
2229+
testing::internal::CaptureStdout();
2230+
// FIXME : This should work with the array of objects as well
2231+
// Cpp::Destruct(where, scope, true, 5);
2232+
Cpp::Destruct(where, scope, true);
2233+
output = testing::internal::GetCapturedStdout();
2234+
EXPECT_EQ(output, "\nDestructor Executed\n");
2235+
output.clear();
2236+
}
2237+
21102238
TEST(FunctionReflectionTest, UndoTest) {
21112239
#ifdef _WIN32
21122240
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";

0 commit comments

Comments
 (0)