256 lines
6.4 KiB
C++
256 lines
6.4 KiB
C++
/*
|
||
DelStash(Test) - verify a facility to memorise and trigger deleter functions
|
||
|
||
Copyright (C)
|
||
2010, Hermann Vosseler <Ichthyostega@web.de>
|
||
|
||
**Lumiera** 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. See the file COPYING for further details.
|
||
|
||
* *****************************************************************/
|
||
|
||
/** @file del-stash-test.cpp
|
||
** unit test \ref DelStash_test
|
||
*/
|
||
|
||
|
||
#include "lib/test/run.hpp"
|
||
#include "lib/del-stash.hpp"
|
||
|
||
|
||
|
||
namespace lib {
|
||
namespace test{
|
||
|
||
namespace { // probe victims
|
||
|
||
ulong MAX_MASS = 200; // number of victims to kill at once
|
||
|
||
ulong checksum = 0;
|
||
|
||
|
||
template<uint siz>
|
||
class Probe
|
||
{
|
||
uint mySiz_;
|
||
char myCrap_[siz];
|
||
|
||
public:
|
||
Probe()
|
||
: mySiz_(siz)
|
||
{
|
||
REQUIRE (siz);
|
||
for (uint i=0; i<siz; ++i)
|
||
{
|
||
char c (rani(256));
|
||
checksum += c;
|
||
myCrap_[i] = c;
|
||
}
|
||
}
|
||
|
||
~Probe()
|
||
{
|
||
CHECK (siz == mySiz_, "using wrong type information for de-allocation");
|
||
for (uint i=0; i<siz; ++i)
|
||
checksum -= myCrap_[i];
|
||
}
|
||
};
|
||
|
||
|
||
template<uint x>
|
||
inline Probe<x>*
|
||
makeViktim ()
|
||
{
|
||
return new Probe<x>();
|
||
}
|
||
|
||
template<uint x>
|
||
inline void
|
||
feedViktim (DelStash& killer)
|
||
{
|
||
killer.manage (new Probe<x>());
|
||
}
|
||
|
||
|
||
}//(End) test data
|
||
|
||
|
||
|
||
|
||
/************************************************************************//**
|
||
* @test create a bunch of objects with varying type and size, memorising
|
||
* how to kill them properly. Verify everyone is dead after mass-kill.
|
||
* Use a checksum not only to verify the number of objects created and
|
||
* destroyed, but also the individual (random) contents of the data
|
||
* within the objects, to ensure that the correct destructor
|
||
* actually is invoked for each type.
|
||
*
|
||
* @see lib::DelStash
|
||
*/
|
||
class DelStash_test : public Test
|
||
{
|
||
|
||
virtual void
|
||
run (Arg)
|
||
{
|
||
seedRand();
|
||
checksum = 0;
|
||
|
||
checkSingleKill();
|
||
checkCustomKill();
|
||
checkMassKill();
|
||
checkAutoKill();
|
||
}
|
||
|
||
|
||
void
|
||
checkSingleKill ()
|
||
{
|
||
DelStash killer;
|
||
CHECK (0 == killer.size());
|
||
|
||
killer.manage<short> (NULL);
|
||
CHECK (0 == killer.size());
|
||
|
||
Probe<5> *p = makeViktim<5>();
|
||
Probe<7> &r = *makeViktim<7>();
|
||
void *v = makeViktim<9>();
|
||
CHECK (0 < checksum);
|
||
|
||
killer.manage (p);
|
||
killer.manage (r);
|
||
killer.manage (static_cast<Probe<9>*> (v));
|
||
|
||
CHECK (3 == killer.size());
|
||
|
||
killer.kill (r);
|
||
CHECK (2 == killer.size());
|
||
|
||
killer.kill (p);
|
||
CHECK (1 == killer.size());
|
||
|
||
killer.kill (p);
|
||
CHECK (1 == killer.size()); // spurious kill requests ignored
|
||
|
||
killer.kill (v);
|
||
CHECK (0 == killer.size());
|
||
CHECK (0 == checksum);
|
||
}
|
||
|
||
|
||
void
|
||
feedViktims (DelStash& killer)
|
||
{
|
||
for (uint i=1; i <= MAX_MASS; ++i)
|
||
switch (i% 5) {
|
||
case 0: feedViktim<12> (killer); break;
|
||
case 1: feedViktim<23> (killer); break;
|
||
case 2: feedViktim<34> (killer); break;
|
||
case 3: feedViktim<45> (killer); break;
|
||
case 4: feedViktim<56> (killer); break;
|
||
}
|
||
}
|
||
|
||
|
||
void
|
||
checkMassKill ()
|
||
{
|
||
DelStash killer;
|
||
CHECK (0 == killer.size());
|
||
|
||
CHECK (0 == checksum);
|
||
CHECK (0 == killer.size());
|
||
|
||
feedViktims (killer);
|
||
CHECK (MAX_MASS == killer.size());
|
||
|
||
killer.killAll();
|
||
CHECK (0 == killer.size());
|
||
CHECK (0 == checksum);
|
||
}
|
||
|
||
|
||
void
|
||
checkAutoKill()
|
||
{
|
||
{
|
||
DelStash killer;
|
||
CHECK (0 == killer.size());
|
||
CHECK (0 == checksum);
|
||
|
||
feedViktims (killer);
|
||
Probe<444> * individuum = makeViktim<444>();
|
||
killer.manage (individuum);
|
||
feedViktims (killer);
|
||
killer.manage (makeViktim<5555>());
|
||
feedViktims (killer);
|
||
|
||
CHECK (3*MAX_MASS + 2 == killer.size());
|
||
|
||
killer.kill(individuum);
|
||
CHECK (3*MAX_MASS + 1 == killer.size());
|
||
|
||
CHECK (0 < checksum);
|
||
}// killer going out of scope...
|
||
|
||
CHECK (0 == checksum);
|
||
}
|
||
|
||
|
||
/** @test use a custom-provided
|
||
* deleter function
|
||
*/
|
||
void
|
||
checkCustomKill ()
|
||
{
|
||
DelStash killer;
|
||
CHECK (0 == killer.size());
|
||
|
||
/** a very specific setup,
|
||
* bound to mess up the checksum,
|
||
* unless the random bias is removed
|
||
* by the custom deleter function
|
||
*/
|
||
class Special
|
||
: Probe<555>
|
||
{
|
||
char secret_;
|
||
|
||
public:
|
||
Special()
|
||
: Probe<555>()
|
||
, secret_('a' + rani('z'-'a' +1))
|
||
{
|
||
checksum += secret_;
|
||
}
|
||
|
||
static void
|
||
selfKill (void *it)
|
||
{
|
||
Special *self = static_cast<Special*> (it);
|
||
checksum -= self->secret_;
|
||
delete self;
|
||
}
|
||
};
|
||
|
||
|
||
void * type_erased = new Special();
|
||
CHECK (0 < checksum);
|
||
|
||
killer.manage (type_erased, &Special::selfKill);
|
||
CHECK (1 == killer.size());
|
||
|
||
killer.kill(type_erased);
|
||
CHECK (0 == killer.size());
|
||
CHECK (0 == checksum);
|
||
}
|
||
};
|
||
|
||
|
||
/** Register this test class... */
|
||
LAUNCHER (DelStash_test, "unit common");
|
||
|
||
|
||
}} // namespace lib::test
|