lumiera_/tests/library/custom-shared-ptr-test.cpp
Ichthyostega 24b3bec4be Doxygen: prepare all unit tests for inclusion in the documentation
Doxygen will only process files with a @file documentation comment.
Up to now, none of our test code has such a comment, preventing the
cross-links to unit tests from working.

This is unfortunate, since unit tests, and even the code comments there,
can be considered as the most useful form of technical documentation.
Thus I'll start an initiative to fill in those missing comments automatically
2017-02-22 01:54:20 +01:00

351 lines
11 KiB
C++

/*
CustomSharedPtr(Test) - ref counting, equality and comparisons
Copyright (C) Lumiera.org
2008, 2010, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file custom-shared-ptr-test.cpp
** unit test §§TODO§§
*/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/util.hpp"
#include "lib/p.hpp"
#include <boost/operators.hpp>
namespace lib {
namespace test{
using std::string;
using std::shared_ptr;
using std::weak_ptr;
using lumiera::error::LUMIERA_ERROR_ASSERTION;
struct X
: boost::totally_ordered<X>
{
long x_;
X(long x=0) : x_(x) {}
operator long () { return x_; }
bool operator< (const X& ox) const { return x_ < ox.x_; }
bool operator== (const X& ox) const { return x_ == ox.x_; }
virtual ~X() {} // using RTTI
};
struct XX : public X
{
long xx_;
XX(long x=0) : X(x), xx_(x+1) {}
};
/************************************************************//**
* @test assure correct behaviour of lumiera's custom shared-ptr,
* including ADL of operators, shared ownership, typing
* and ordering
* @see lumiera::P
*/
class CustomSharedPtr_test : public Test
{
virtual void
run (Arg)
{
check_refcounting ();
check_shared_ownership ();
check_ownership_transfer ();
check_type_relations ();
check_ordering ();
}
/** @test smart-ptr basic behaviour */
void
check_refcounting ()
{
P<X> p1 (new X(7));
CHECK (p1);
CHECK (1 == p1.use_count());
CHECK (7 == p1->x_);
{
P<X> p2 (new X(9));
CHECK (1 == p2.use_count());
p2.swap (p1);
CHECK (1 == p1.use_count());
CHECK (1 == p2.use_count());
p2 = p1;
CHECK (2 == p1.use_count());
CHECK (2 == p2.use_count());
}
CHECK (1 == p1.use_count());
CHECK (9 == p1->x_);
p1.reset();
CHECK (0 == p1.use_count());
CHECK (!p1);
}
/** @test cooperation with other shared-ptr types */
void
check_shared_ownership ()
{
P<X> pX (new X(22));
CHECK (pX);
CHECK (1 == pX.use_count());
weak_ptr<X> wX (pX);
CHECK (wX.lock());
CHECK (1 == pX.use_count());
shared_ptr<X> sp1 (wX);
shared_ptr<X> sp2 (pX);
shared_ptr<X> sp3; sp3 = pX;
CHECK (22 == sp3->x_);
CHECK (4 == pX.use_count());
CHECK (*pX == *sp1);
CHECK (*sp1 == *sp2);
CHECK (*sp2 == *sp3);
P<X> pX2;
pX2.swap(pX);
CHECK (!pX);
CHECK (0 == pX.use_count());
CHECK (4 == pX2.use_count());
P<X, P<X> > pXX (pX2); // a different type, but compatible pointers
pX2 = pX;
CHECK (!pX2);
CHECK (0 == pX2.use_count());
CHECK (4 == pXX.use_count());
sp3 = sp2 = sp1 = pX;
CHECK (22 == pXX->x_);
CHECK (1 == pXX.use_count());
CHECK (!sp1);
CHECK (!sp2);
CHECK (!sp3);
CHECK (22 == wX.lock()->x_);
CHECK (1 == pXX.use_count());
pXX.reset();
CHECK (!pXX);
CHECK (!wX.lock());
}
void
check_ownership_transfer ()
{
std::auto_ptr<X> au (new X(23));
CHECK (au.get());
P<X> pX (std::move(au));
CHECK (!au.get());
CHECK (pX);
CHECK (1 == pX.use_count());
CHECK (23 == pX->x_);
au.reset (new X(21));
CHECK (au.get());
pX.reset();
CHECK (!pX);
CHECK (0 == pX.use_count());
pX = std::move(au);
CHECK (!au.get());
CHECK (pX);
CHECK (1 == pX.use_count());
CHECK (21 == pX->x_);
}
/** @test building type relationships on smart-ptrs */
void
check_type_relations ()
{
P<X> pX; // Base: shared_ptr<X>
P<XX> pX1; // Base: shared_ptr<XX>
P<XX,P<X> > pX2; // Base: P<X>
P<XX,shared_ptr<X> > pX3; // Base: shared_ptr<X>
P<XX,shared_ptr<long> > pLo;// Base: shared_ptr<long> (rather nonsense, but well...)
P<X,string> pLoL; // Base: std::string
P<string> pLoLoL; // Base: shared_ptr<string>
CHECK (INSTANCEOF (shared_ptr<X>, &pX));
CHECK ( INSTANCEOF (shared_ptr<XX>, &pX1));
// CHECK (!INSTANCEOF (shared_ptr<X>, &pX1)); // doesn't compile (no RTTI) -- that's correct
// CHECK (!INSTANCEOF (P<X>, &pX1)); // similar, type mismatch detected by compiler
CHECK ( INSTANCEOF (shared_ptr<X>, &pX2));
// CHECK (!INSTANCEOF (shared_ptr<XX>, &pX2));
CHECK ( INSTANCEOF (P<X>, &pX2));
CHECK ( INSTANCEOF (shared_ptr<X>, &pX3));
// CHECK (!INSTANCEOF (shared_ptr<XX>, &pX3));
// CHECK (!INSTANCEOF (P<X>, &pX3));
CHECK ( INSTANCEOF (shared_ptr<long>, &pLo));
// CHECK (!INSTANCEOF (shared_ptr<X>, &pLo));
// CHECK (!INSTANCEOF (P<X>, &pLo));
// CHECK (!INSTANCEOF (shared_ptr<long>, &pLoL));
// CHECK (!INSTANCEOF (shared_ptr<X>, &pLoL));
// CHECK (!INSTANCEOF (P<X>, &pLoL));
CHECK ( INSTANCEOF (string, &pLoL));
CHECK ( INSTANCEOF (shared_ptr<string>, &pLoLoL));
// CHECK (!INSTANCEOF (string, &pLoLoL));
// CHECK (!INSTANCEOF (shared_ptr<X>, &pLoLoL));
pX = pX1; // OK: pointee subtype...
pX = pX2; // invokes shared_ptr<X>::operator= (shared_ptr<X> const&)
pX = pX3;
// pX = pLo; // similar, but long* not assignable to X*
// pX = pLoL; // similar, but string* not assignable to X*
// pX = pLoLoL; // same...
// you won't be able to do much with the "LoLo"-Types,
// as their types and pointee types's relations don't match
pX.reset (new XX(5));
CHECK (5 == *pX); // implicit conversion from X to long
pX2 = pX; // works, because both are implemented in terms of shared_ptr<X>
CHECK (5 == pX2->x_);
CHECK (6 == pX2->xx_); // using the XX interface (performing dynamic downcast)
pX3.reset (new X(7)); // again works because implemented in terms of shared_ptr<X>
pX2 = pX3; // same
CHECK (pX2); // both contain indeed a valid pointer....
CHECK (pX3);
CHECK (! pX2.get()); // but dynamic cast to XX at access fails
CHECK (! pX3.get());
}
/** @test equality and ordering operators forwarded to pointee */
void
check_ordering ()
{
typedef P<X> PX;
typedef P<XX,PX> PXX;
PX pX1 (new X(3));
PX pX2 (new XX(5));
PX pX3, pX4, pX5, pX6;
PXX pXX (new XX(7));
pX3 = pXX;
pX4.reset(new X(*pXX));
CHECK ( (pX1 == pX1)); // reflexivity
CHECK (!(pX1 != pX1));
CHECK (!(pX1 < pX1));
CHECK (!(pX1 > pX1));
CHECK ( (pX1 <= pX1));
CHECK ( (pX1 >= pX1));
CHECK (!(pX1 == pX2)); // compare to same ptr type with larger pointee of subtype
CHECK ( (pX1 != pX2));
CHECK ( (pX1 < pX2));
CHECK (!(pX1 > pX2));
CHECK ( (pX1 <= pX2));
CHECK (!(pX1 >= pX2));
CHECK (!(pX2 == pXX)); // compare to ptr subtype with larger pointee of same subtype
CHECK ( (pX2 != pXX));
CHECK ( (pX2 < pXX));
CHECK (!(pX2 > pXX));
CHECK ( (pX2 <= pXX));
CHECK (!(pX2 >= pXX));
CHECK (!(pX1 == pXX)); // transitively compare to ptr subtype with larger pointee of subtype
CHECK ( (pX1 != pXX));
CHECK ( (pX1 < pXX));
CHECK (!(pX1 > pXX));
CHECK ( (pX1 <= pXX));
CHECK (!(pX1 >= pXX));
CHECK ( (pX3 == pXX)); // compare ptr to subtype ptr both referring to same pointee
CHECK (!(pX3 != pXX));
CHECK (!(pX3 < pXX));
CHECK (!(pX3 > pXX));
CHECK ( (pX3 <= pXX));
CHECK ( (pX3 >= pXX));
CHECK ( (pX4 == pXX)); // compare ptr to subtype ptr both referring to different but equal pointees
CHECK (!(pX4 != pXX));
CHECK (!(pX4 < pXX));
CHECK (!(pX4 > pXX));
CHECK ( (pX4 <= pXX));
CHECK ( (pX4 >= pXX));
CHECK (!(pXX == pX5)); // compare subtype ptr to empty ptr: "unequal but not orderable"
CHECK ( (pXX != pX5));
CHECK ( (pX5 == pX6)); // compare two empty ptrs: "equal, equivalent but not orderable"
CHECK (!(pX5 != pX6));
// order relations on NIL pointers disallowed
#if false ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
VERIFY_ERROR (ASSERTION, pXX < pX5 );
VERIFY_ERROR (ASSERTION, pXX > pX5 );
VERIFY_ERROR (ASSERTION, pXX <= pX5 );
VERIFY_ERROR (ASSERTION, pXX >= pX5 );
VERIFY_ERROR (ASSERTION, pX5 < pXX );
VERIFY_ERROR (ASSERTION, pX5 > pXX );
VERIFY_ERROR (ASSERTION, pX5 <= pXX );
VERIFY_ERROR (ASSERTION, pX5 >= pXX );
VERIFY_ERROR (ASSERTION, pX5 < pX6 );
VERIFY_ERROR (ASSERTION, pX5 > pX6 );
VERIFY_ERROR (ASSERTION, pX5 <= pX6 );
VERIFY_ERROR (ASSERTION, pX5 >= pX6 );
#endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
}
};
/** Register this test class... */
LAUNCHER (CustomSharedPtr_test, "unit common");
}} // namespace lib::test