Files
simgear/simgear/nasal/cppbind/test/cppbind_test_ghost.cxx
T

233 lines
7.1 KiB
C++

#define BOOST_TEST_MODULE cppbind
#include <BoostTestTargetConfig.h>
#include "TestContext.hxx"
#include <simgear/nasal/cppbind/Ghost.hxx>
#include <simgear/nasal/cppbind/NasalContext.hxx>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
class Base1:
public virtual SGVirtualWeakReferenced
{};
class Base2:
public virtual SGVirtualWeakReferenced
{};
class Derived:
public Base1,
public Base2
{};
typedef SGSharedPtr<Base1> Base1Ptr;
typedef SGSharedPtr<Base2> Base2Ptr;
typedef SGSharedPtr<Derived> DerivedPtr;
typedef SGWeakPtr<Derived> DerivedWeakPtr;
typedef SGSharedPtr<SGReferenced> SGReferencedPtr;
// Check if shared_ptr_traits give correct types for strong and weak shared
// pointer
#define CHECK_PTR_TRAIT_TYPE(ptr_t, type_name, type)\
BOOST_STATIC_ASSERT((boost::is_same<\
nasal::shared_ptr_traits<ptr_t>::type_name,\
type\
>::value));
#define CHECK_PTR_TRAIT(ref, weak)\
CHECK_PTR_TRAIT_TYPE(ref, strong_ref, ref)\
CHECK_PTR_TRAIT_TYPE(weak, weak_ref, weak)\
CHECK_PTR_TRAIT(DerivedPtr, DerivedWeakPtr)
CHECK_PTR_TRAIT(boost::shared_ptr<Base1>, boost::weak_ptr<Base1>)
#undef CHECK_PTR_TRAIT
#undef CHECK_PTR_TRAIT_TYPE
BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<Base1Ptr>::value));
BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<Base2Ptr>::value));
BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedPtr>::value));
BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedWeakPtr>::value));
BOOST_STATIC_ASSERT((!nasal::supports_weak_ref<SGReferencedPtr>::value));
static void setupGhosts()
{
nasal::Ghost<Base1Ptr>::init("Base1");
nasal::Ghost<Base2Ptr>::init("Base2");
nasal::Ghost<DerivedPtr>::init("Derived")
.bases<Base1Ptr>()
.bases<Base2Ptr>();
}
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
{
setupGhosts();
naContext c = naNewContext();
DerivedPtr d = new Derived();
DerivedWeakPtr weak(d);
// store weak pointer and extract strong pointer
naRef na_d = nasal::to_nasal(c, DerivedWeakPtr(d));
BOOST_REQUIRE( naIsGhost(na_d) );
BOOST_CHECK_EQUAL( nasal::from_nasal<Base1Ptr>(c, na_d), d );
BOOST_CHECK_EQUAL( nasal::from_nasal<Base2Ptr>(c, na_d), d );
BOOST_CHECK_EQUAL( nasal::from_nasal<DerivedPtr>(c, na_d), d );
d.reset();
BOOST_REQUIRE_THROW( nasal::from_nasal<DerivedPtr>(c, na_d),
nasal::bad_nasal_cast );
// store strong pointer and extract weak pointer
d.reset(new Derived);
na_d = nasal::to_nasal(c, d);
BOOST_REQUIRE( naIsGhost(na_d) );
weak = nasal::from_nasal<DerivedWeakPtr>(c, na_d);
BOOST_CHECK_EQUAL( weak.lock(), d );
d.reset();
BOOST_REQUIRE( nasal::from_nasal<DerivedPtr>(c, na_d) );
BOOST_REQUIRE( weak.lock() );
naFreeContext(c);
naGC();
nasal::ghostProcessDestroyList();
BOOST_REQUIRE( !weak.lock() );
}
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( ghost_casting_storage )
{
setupGhosts();
nasal::Context c;
// Check converting to and from every class in the hierarchy for an instance
// of the leaf class
DerivedPtr d = new Derived();
naRef na_d = nasal::to_nasal(c, d),
na_b1 = nasal::to_nasal(c, Base1Ptr(d)),
na_b2 = nasal::to_nasal(c, Base2Ptr(d));
Derived *d0 = nasal::from_nasal<Derived*>(c, na_d),
*d1 = nasal::from_nasal<Derived*>(c, na_b1),
*d2 = nasal::from_nasal<Derived*>(c, na_b2);
BOOST_CHECK_EQUAL(d0, d.get());
BOOST_CHECK_EQUAL(d1, d.get());
BOOST_CHECK_EQUAL(d2, d.get());
Base1 *b1 = nasal::from_nasal<Base1*>(c, na_b1);
BOOST_CHECK_EQUAL(b1, static_cast<Base1*>(d.get()));
Base2 *b2 = nasal::from_nasal<Base2*>(c, na_b2);
BOOST_CHECK_EQUAL(b2, static_cast<Base2*>(d.get()));
// Check converting from base class instance to derived classes is not
// possible
Base1Ptr b1_ref = new Base1();
na_b1 = nasal::to_nasal(c, b1_ref);
BOOST_CHECK_EQUAL(nasal::from_nasal<Base1*>(c, na_b1), b1_ref.get());
BOOST_CHECK_THROW(nasal::from_nasal<Base2*>(c, na_b1), nasal::bad_nasal_cast);
BOOST_CHECK_THROW(nasal::from_nasal<Derived*>(c, na_b1), nasal::bad_nasal_cast);
}
//------------------------------------------------------------------------------
#define CHECK_PTR_STORAGE_TRAIT_TYPE(ptr_t, storage)\
BOOST_STATIC_ASSERT((boost::is_same<\
nasal::shared_ptr_storage<ptr_t>::storage_type,\
storage\
>::value));
CHECK_PTR_STORAGE_TRAIT_TYPE(DerivedPtr, Derived)
CHECK_PTR_STORAGE_TRAIT_TYPE(DerivedWeakPtr, DerivedWeakPtr)
typedef boost::shared_ptr<Derived> BoostDerivedPtr;
CHECK_PTR_STORAGE_TRAIT_TYPE(BoostDerivedPtr, BoostDerivedPtr)
typedef boost::weak_ptr<Derived> BoostDerivedWeakPtr;
CHECK_PTR_STORAGE_TRAIT_TYPE(BoostDerivedWeakPtr, BoostDerivedWeakPtr)
#undef CHECK_PTR_STORAGE_TRAIT_TYPE
BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<Base1Ptr>::is_intrusive::value));
BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<Base2Ptr>::is_intrusive::value));
BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<DerivedPtr>::is_intrusive::value));
BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<DerivedWeakPtr>::is_intrusive::value));
BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<SGReferencedPtr>::is_intrusive::value));
BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<boost::shared_ptr<Derived> >::is_intrusive::value));
BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<boost::weak_ptr<Derived> >::is_intrusive::value));
BOOST_AUTO_TEST_CASE( storage_traits )
{
DerivedPtr d = new Derived();
Derived* d_raw = nasal::shared_ptr_storage<DerivedPtr>::ref(d);
BOOST_REQUIRE_EQUAL(d_raw, d.get());
BOOST_REQUIRE_EQUAL(d.getNumRefs(), 2);
DerivedWeakPtr* d_weak = nasal::shared_ptr_storage<DerivedWeakPtr>::ref(d);
BOOST_REQUIRE_EQUAL(
nasal::shared_ptr_storage<DerivedWeakPtr>::get<Derived*>(d_weak),
d_raw
);
d.reset();
BOOST_REQUIRE_EQUAL(Derived::count(d_raw), 1);
nasal::shared_ptr_storage<DerivedPtr>::unref(d_raw);
BOOST_REQUIRE(d_weak->expired());
nasal::shared_ptr_storage<DerivedWeakPtr>::unref(d_weak);
}
BOOST_AUTO_TEST_CASE( bind_methods )
{
struct TestClass
{
int arg1;
std::string arg2;
std::string arg3;
int arg4;
void set(int a1, const std::string& a2, const std::string& a3, int a4)
{
arg1 = a1;
arg2 = a2;
arg3 = a3;
arg4 = a4;
}
};
using TestClassPtr = boost::shared_ptr<TestClass>;
auto set_func = boost::function<
void (TestClass&, int, const std::string&, const std::string&, int)
>(&TestClass::set);
nasal::Ghost<TestClassPtr>::init("TestClass")
.method("set", set_func)
.method("setReverse", set_func, std::index_sequence<3,2,1,0>{});
TestContext ctx;
auto test = boost::make_shared<TestClass>();
ctx.exec("me.set(1, \"s2\", \"s3\", 4);", ctx.to_me(test));
BOOST_CHECK_EQUAL(test->arg1, 1);
BOOST_CHECK_EQUAL(test->arg2, "s2");
BOOST_CHECK_EQUAL(test->arg3, "s3");
BOOST_CHECK_EQUAL(test->arg4, 4);
ctx.exec("me.setReverse(1, \"s2\", \"s3\", 4);", ctx.to_me(test));
BOOST_CHECK_EQUAL(test->arg1, 4);
BOOST_CHECK_EQUAL(test->arg2, "s3");
BOOST_CHECK_EQUAL(test->arg3, "s2");
BOOST_CHECK_EQUAL(test->arg4, 1);
}