Skip to content

Commit

Permalink
[PyROOT] Add tests of automatic injection of move
Browse files Browse the repository at this point in the history
Test that we automatically inject an `std::move` in the TClingCallFunc wrapper call in cases where a copy constructor is not available for the class.
  • Loading branch information
vepadulano committed Feb 1, 2024
1 parent 4784b0d commit 1c7a439
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 0 deletions.
3 changes: 3 additions & 0 deletions bindings/pyroot/pythonizations/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,6 @@ endif()

# TComplex pythonizations
ROOT_ADD_PYUNITTEST(pyroot_tcomplex tcomplex_operators.py)

# Test pass-by-value semantics for types with a deleted copy-constructor
ROOT_ADD_PYUNITTEST(callfuncwrappers callfuncwrappers.py)
61 changes: 61 additions & 0 deletions bindings/pyroot/pythonizations/test/callfuncwrappers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import unittest
import ROOT


class CallFuncWrappers(unittest.TestCase):
"""
Tests for pass-by-value semantics of classes with deleted copy constructor
"""

def test_pass_by_value_unique_ptr(self):
"""
It is possible to pass a unique_ptr by value in a function call,
whether it is a default argument or not
"""
ROOT.gInterpreter.Declare(r'''
struct uptrtype{
int mVal{42};
uptrtype() {}
uptrtype(int val): mVal(val) {}
};
int foo(std::unique_ptr<uptrtype> ptr = std::make_unique<uptrtype>()) { return ptr->mVal; }
''')

# The correct value is returned by the default argument
self.assertEqual(ROOT.foo(), 42)

# Creating a unique_ptr explicitly is also valid
ptr = ROOT.std.make_unique[ROOT.uptrtype](33)
self.assertEqual(ROOT.foo(ptr), 33)

def test_pass_by_value_templated_move_constructor(self):
"""
It is possible to pass a class with a deleted copy constructor
and a templated move constructor in a function by value
"""
ROOT.gInterpreter.Declare(r'''
struct templmovetype{
int mVal{42};
templmovetype() {}
templmovetype(int val): mVal(val) {}
templmovetype(const templmovetype&) = delete;
template<typename T = int>
templmovetype(templmovetype &&other): mVal(other.mVal) {}
};
int foo(templmovetype val = templmovetype{}) { return val.mVal; }
''')

# The correct value is returned by the default argument
self.assertEqual(ROOT.foo(), 42)

val = ROOT.templmovetype(33)
self.assertEqual(ROOT.foo(val), 33)

self.assertEqual(ROOT.foo(ROOT.templmovetype(55)), 55)


if __name__ == '__main__':
unittest.main()
38 changes: 38 additions & 0 deletions core/metacling/test/TClingCallFuncTests.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,41 @@ TEST(TClingCallFunc, ROOT_6523) {
break;
}
}

TEST(TClingCallFunc, FunctionWrapperUniquePtr)
{
gInterpreter->Declare(R"cpp(
struct FunctionWrapperUniquePtr{
int mVal{42};
FunctionWrapperUniquePtr() {}
FunctionWrapperUniquePtr(int val): mVal(val) {}
};
int foo(
std::unique_ptr<FunctionWrapperUniquePtr> ptr = std::make_unique<FunctionWrapperUniquePtr>())
{
return ptr->mVal;
}
)cpp");

CallFuncRAII CfRAII("", "foo", "std::unique_ptr<FunctionWrapperUniquePtr>");
std::string wrapper = CfRAII.GetWrapper();
ASSERT_TRUE(gInterpreter->Declare(wrapper.c_str()));
}

TEST(TClingCallFunc, FunctionWrapperTemplatedMoveConstructor)
{
gInterpreter->Declare(R"cpp(
struct FunctionWrapperTemplatedMoveConstructor{
int mVal{42};
FunctionWrapperTemplatedMoveConstructor() {}
FunctionWrapperTemplatedMoveConstructor(const FunctionWrapperTemplatedMoveConstructor&) = delete;
template<typename T = int>
FunctionWrapperTemplatedMoveConstructor(FunctionWrapperTemplatedMoveConstructor &&) {}
};
int foo(FunctionWrapperTemplatedMoveConstructor a = FunctionWrapperTemplatedMoveConstructor{}) { return a.mVal; }
)cpp");

CallFuncRAII CfRAII("", "foo", "FunctionWrapperTemplatedMoveConstructor");
std::string wrapper = CfRAII.GetWrapper();
ASSERT_TRUE(gInterpreter->Declare(wrapper.c_str()));
}

0 comments on commit 1c7a439

Please # to comment.