Notably some links on the **Gnome documentation** pages are problematic, since there was seemingly an infrastructure change -- which unfortunately leads to loosing several deep-links into the GTK-3 related documentation and tutorials. While the differences to GTK-4 are often rather minimal, I would still prefer to link to those documentation pages used as reference at implementation time of our related library and GUI functionality. In several cases I have thus looked up the old URLs at Archive.org
220 lines
7.3 KiB
C++
220 lines
7.3 KiB
C++
/*
|
||
UtilIdentity(Test) - helpers for identity and memory location
|
||
|
||
Copyright (C)
|
||
2024, 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 util-identity-test.cpp
|
||
** unit test \ref UtilIdentity_test
|
||
*/
|
||
|
||
|
||
#include "lib/test/run.hpp"
|
||
#include "lib/format-obj.hpp"
|
||
#include "lib/util.hpp"
|
||
|
||
#include <utility>
|
||
#include <string>
|
||
|
||
using std::move;
|
||
using std::string;
|
||
|
||
|
||
namespace util {
|
||
namespace test {
|
||
|
||
|
||
|
||
/*****************************************************************//**
|
||
* @test verify identity based on memory address location,
|
||
* which can be relevant for custom allocation schemes
|
||
* and to prevent self-assignment.
|
||
* - access to a given entitie's address is used as foundation,
|
||
* with the _special twist_ that a pointer is »unpacked«
|
||
* - based on this address, an ID-number can be generated
|
||
* - moreover, two flavours of identity check are provided
|
||
* + util::isSameObject compares at the level of the
|
||
* _language object_ — it takes its arguments _solely_
|
||
* by reference and does not »unpack« a pointer.
|
||
* The term [object] is used here as in the C++ standard
|
||
* + util::isSameAdr accepts any mix of references and
|
||
* pointers, disregarding any type information, thereby
|
||
* _»unpacking«_ the address information contained in a
|
||
* pointer is (i.e. the address of the pointee is used)
|
||
* [object]: https://en.cppreference.com/w/cpp/language/type.html
|
||
*/
|
||
class UtilIdentity_test : public Test
|
||
{
|
||
|
||
void
|
||
run (Arg)
|
||
{
|
||
verify_getAdr();
|
||
verify_addrID();
|
||
verify_isSameAdr();
|
||
verify_isSameObject();
|
||
}
|
||
|
||
|
||
/** @test determine the address of an referred entity,
|
||
* possibly _unpacking_ a pointer (using its content)
|
||
*/
|
||
void
|
||
verify_getAdr()
|
||
{
|
||
CHECK (getAdr (this) == this);
|
||
CHECK (getAdr (*this) == this);
|
||
|
||
CStr aloof[2] = {"reality", "check"};
|
||
CHECK (getAdr (aloof) == &aloof);
|
||
CHECK (getAdr (&aloof[0]) == &aloof);
|
||
CHECK (getAdr (&aloof[1]) == aloof+1);
|
||
CHECK (getAdr ( aloof[0]) == aloof[0]);
|
||
CHECK (getAdr ( aloof[1]) == aloof[1]);
|
||
}
|
||
|
||
/** @test generate a numeric ID based on the memory address. */
|
||
void
|
||
verify_addrID()
|
||
{
|
||
uint ui[2] = {2,3};
|
||
CHECK (addrID (ui[1]) == addrID (ui[0]) + sizeof(uint));
|
||
|
||
uint* up{ui+1};
|
||
CHECK (addrID (ui[1]) == addrID (up));
|
||
}
|
||
|
||
|
||
/** dummy entity to compare */
|
||
struct Boo
|
||
{
|
||
short moo;
|
||
string woo;
|
||
|
||
Boo()
|
||
: moo(rani(1000))
|
||
, woo{toString(moo-1)}
|
||
{ }
|
||
};
|
||
|
||
struct SuBoo : Boo
|
||
{
|
||
using Boo::Boo;
|
||
size_t poo{addrID (this)};
|
||
};
|
||
|
||
static Boo* asBoo (void* mem) { return static_cast<Boo*> (mem); }
|
||
|
||
|
||
/** @test determine identity of referred arguments based on their
|
||
* memory location; pointers are unpacked, referring to the pointee.
|
||
*/
|
||
void
|
||
verify_isSameAdr()
|
||
{
|
||
Boo boo;
|
||
Boo booo;
|
||
Boo* boop = &boo;
|
||
Boo const* const beep = boop;
|
||
CHECK (boo.moo != booo.moo);
|
||
CHECK (boo.moo == boop->moo);
|
||
CHECK ( isSameAdr (boop, beep));
|
||
CHECK (not isSameAdr (&boop,&beep));
|
||
CHECK ( isSameAdr (boo, beep));
|
||
CHECK ( isSameAdr (*beep, boo ));
|
||
CHECK (not isSameAdr (*beep, booo));
|
||
CHECK ( isSameAdr (boo, boo.moo));
|
||
CHECK ( isSameAdr (boo, &boo.moo));
|
||
CHECK (not isSameAdr (boo.moo, booo));
|
||
CHECK ( isSameAdr (booo, asBoo(&booo.moo)));
|
||
CHECK (not isSameAdr (booo, asBoo(&booo.woo)));
|
||
|
||
// handles also void*
|
||
const void* voo = boop;
|
||
CHECK ( isSameAdr (voo, boo));
|
||
CHECK ( isSameAdr (voo, boop));
|
||
CHECK (not isSameAdr (voo, booo));
|
||
CHECK ( isSameAdr (voo, asBoo(&boo.moo)));
|
||
CHECK (not isSameAdr (voo, asBoo(&booo.moo)));
|
||
CHECK (not isSameAdr (voo, asBoo(&boo.woo)));
|
||
|
||
// RValue taken by ref
|
||
Boo&& roo = move(boo);
|
||
CHECK ( isSameAdr (roo, boo));
|
||
CHECK ( isSameAdr (voo, roo));
|
||
CHECK (not isSameAdr (voo, Boo{roo}));
|
||
|
||
// type information disregarded
|
||
SuBoo* suBoo = static_cast<SuBoo*>(&boo);
|
||
CHECK ( isSameAdr (boo, suBoo));
|
||
CHECK ( isSameAdr (boo, suBoo->moo));
|
||
CHECK ( isSameAdr (voo, suBoo->moo));
|
||
CHECK (not isSameAdr (voo, suBoo->poo));
|
||
|
||
SuBoo sudo{*suBoo};
|
||
CHECK (not isSameAdr (sudo, boo));
|
||
CHECK (not isSameAdr (sudo, suBoo));
|
||
suBoo = &sudo;
|
||
CHECK ( isSameAdr (sudo.poo, suBoo->poo));
|
||
}
|
||
|
||
/** @test determine strictly the identity of referred entities as given. */
|
||
void
|
||
verify_isSameObject()
|
||
{
|
||
Boo boo;
|
||
Boo booo;
|
||
Boo* boop = &boo;
|
||
Boo* woop = boop;
|
||
Boo& foop = *woop;
|
||
CHECK ( isSameObject (boo, boo ));
|
||
CHECK ( isSameObject (booo, booo));
|
||
CHECK (not isSameObject (boo, booo));
|
||
CHECK (not isSameObject (booo, boo ));
|
||
// pointers count as »objects« and are not dereferenced
|
||
CHECK (not isSameObject (boop, woop));
|
||
CHECK (not isSameObject (boop, booo));
|
||
CHECK (not isSameObject (boop, boo ));
|
||
CHECK (not isSameObject (booo, woop));
|
||
CHECK (not isSameObject (boo , woop));
|
||
CHECK ( isSameObject (boo , foop));
|
||
CHECK ( isSameObject (foop, boo ));
|
||
CHECK (not isSameObject (foop, boop));
|
||
CHECK (not isSameObject (foop, woop));
|
||
CHECK (not isSameObject (foop, &boo ));
|
||
CHECK ( isSameObject (foop, *boop));
|
||
CHECK ( isSameObject (*boop, foop));
|
||
|
||
// RValue taken by ref
|
||
Boo&& roo = move(boo);
|
||
CHECK ( isSameObject (roo, boo));
|
||
CHECK (not isSameObject (boo, Boo{roo}));
|
||
|
||
// type information disregarded
|
||
SuBoo* suBoo = static_cast<SuBoo*>(&boo);
|
||
CHECK ( isSameObject (boo, *suBoo));
|
||
CHECK ( isSameObject (boo, suBoo->moo));
|
||
CHECK (not isSameObject (boo, suBoo->woo));
|
||
|
||
// void* is treated as a distinct object
|
||
void* voo = boop;
|
||
CHECK (not isSameObject (voo , boop));
|
||
CHECK (not isSameObject (voo , boo));
|
||
CHECK (not isSameObject (voo , &boo)); // ...not getting anywhere...
|
||
CHECK (not isSameObject (voo , asBoo(&boo)));
|
||
CHECK (not isSameObject (boo , asBoo(&boo)));
|
||
}
|
||
};
|
||
|
||
|
||
LAUNCHER (UtilIdentity_test, "unit common");
|
||
|
||
}} // namespace util::test
|
||
|