* Copyright 2022 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Niels Sascha Reedijk, niels.reedijk@gmail.com
*/
#include "ExclusiveBorrowTest.h"
#include <atomic>
#include <tuple>
#include <cppunit/TestCaller.h>
#include <cppunit/TestSuite.h>
#include <ExclusiveBorrow.h>
using BPrivate::Network::BBorrow;
using BPrivate::Network::BBorrowError;
using BPrivate::Network::BExclusiveBorrow;
using BPrivate::Network::make_exclusive_borrow;
class DeleteTestHelper
{
public:
DeleteTestHelper(std::atomic<bool>& deleted)
:
fDeleted(deleted)
{
}
~DeleteTestHelper() { fDeleted.store(true); }
private:
std::atomic<bool>& fDeleted;
};
class Base
{
public:
Base() {}
virtual ~Base() {}
virtual bool IsDerived() { return false; }
};
class Derived : public Base
{
public:
Derived() {}
virtual ~Derived() {}
virtual bool IsDerived() override { return true; }
};
ExclusiveBorrowTest::ExclusiveBorrowTest()
{
}
void
ExclusiveBorrowTest::ObjectDeleteTest()
{
std::atomic<bool> deleted = false;
{
auto object = make_exclusive_borrow<DeleteTestHelper>(deleted);
}
CPPUNIT_ASSERT_EQUAL_MESSAGE("(1) Expected object to be deleted", true, deleted.load());
deleted.store(false);
{
auto object = make_exclusive_borrow<DeleteTestHelper>(deleted);
{
auto borrow = BBorrow<DeleteTestHelper>(object);
}
CPPUNIT_ASSERT_EQUAL_MESSAGE("(2) Object should not be deleted", false, deleted.load());
}
CPPUNIT_ASSERT_EQUAL_MESSAGE("(2) Expected object to be deleted", true, deleted.load());
deleted.store(false);
{
auto borrow = BBorrow<DeleteTestHelper>(nullptr);
{
auto object = make_exclusive_borrow<DeleteTestHelper>(deleted);
borrow = BBorrow<DeleteTestHelper>(object);
}
CPPUNIT_ASSERT_EQUAL_MESSAGE("(3) Object should not be deleted", false, deleted.load());
}
CPPUNIT_ASSERT_EQUAL_MESSAGE("(3) Expected object to be deleted", true, deleted.load());
}
void
ExclusiveBorrowTest::OwnershipTest()
{
auto ownedObject = make_exclusive_borrow<int>(1);
CPPUNIT_ASSERT(*ownedObject == 1);
auto borrow = BBorrow<int>(ownedObject);
try {
std::ignore = *ownedObject == 1;
CPPUNIT_FAIL("Unexpected access to the owned object while borrowed");
} catch (const BBorrowError& e) {
}
try {
std::ignore = *borrow == 1;
} catch (const BBorrowError& e) {
CPPUNIT_FAIL("Unexpected error accessing the borrowed object");
}
try {
auto borrowAgain = BBorrow<int>(ownedObject);
CPPUNIT_FAIL("Unexpectedly able to borrow the owned object again");
} catch (const BBorrowError& e) {
}
try {
borrow = BBorrow<int>(nullptr);
std::ignore = *borrow == 1;
CPPUNIT_FAIL("Unexpected access to an empty borrowed object");
} catch (const BBorrowError& e) {
}
try {
std::ignore = *ownedObject == 1;
} catch (const BBorrowError& e) {
CPPUNIT_FAIL("Unexpected error accessing the owned object");
}
}
void
ExclusiveBorrowTest::PolymorphismTest()
{
auto owned = make_exclusive_borrow<Derived>();
{
auto borrowDerived = BBorrow<Derived>(owned);
CPPUNIT_ASSERT_EQUAL(true, borrowDerived->IsDerived());
}
{
auto borrowBase = BBorrow<Base>(owned);
CPPUNIT_ASSERT_EQUAL(true, borrowBase->IsDerived());
}
}
void
ExclusiveBorrowTest::ReleaseTest()
{
auto ownedObject = make_exclusive_borrow<int>(1);
auto ownedPointer = std::addressof(*ownedObject);
try {
auto borrow = BBorrow<int>(ownedObject);
auto invalidClaimedPointer = ownedObject.Release();
CPPUNIT_FAIL("Unexpectedly able to release a borrowed pointer");
} catch (const BBorrowError&) {
}
auto validClaimedPointer = ownedObject.Release();
CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected released pointer to point to the same object",
validClaimedPointer.get(), ownedPointer);
}
void
ExclusiveBorrowTest::AddTests(BTestSuite& parent)
{
CppUnit::TestSuite& suite = *new CppUnit::TestSuite("ExclusiveBorrowTest");
suite.addTest(new CppUnit::TestCaller<ExclusiveBorrowTest>(
"ExclusiveBorrowTest::ObjectDeleteTest", &ExclusiveBorrowTest::ObjectDeleteTest));
suite.addTest(new CppUnit::TestCaller<ExclusiveBorrowTest>(
"ExclusiveBorrowTest::OwnershipTest", &ExclusiveBorrowTest::OwnershipTest));
suite.addTest(new CppUnit::TestCaller<ExclusiveBorrowTest>(
"ExclusiveBorrowTest::PolymorphismTest", &ExclusiveBorrowTest::PolymorphismTest));
suite.addTest(new CppUnit::TestCaller<ExclusiveBorrowTest>(
"ExclusiveBorrowTest::ReleaseTest", &ExclusiveBorrowTest::ReleaseTest));
parent.addTest("ExclusiveBorrowTest", &suite);
}