LUMIERA.clone/tests/library/advice/advice-basics-test.cpp
Ichthyostega 0b9e184fa3 Library: replace usages of rand() in the whole code base
* most usages are drop-in replacements
 * occasionally the other convenience functions can be used
 * verify call-paths from core code to identify usages
 * ensure reseeding for all tests involving some kind of randomness...

__Note__: some tests were not yet converted,
since their usage of randomness is actually not thread-safe.
This problem existed previously, since also `rand()` is not thread safe,
albeit in most cases it is possible to ignore this problem, as
''garbled internal state'' is also somehow „random“
2024-11-13 04:23:46 +01:00

268 lines
7.8 KiB
C++

/*
AdviceBasics(Test) - basic behaviour of the Advice collaboration
Copyright (C) Lumiera.org
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 advice-basics-test.cpp
** unit test \ref AdviceBasics_test
*/
#include "lib/test/run.hpp"
#include "common/advice.hpp"
namespace lumiera {
namespace advice {
namespace test {
namespace { // Some test classes using the advice system...
class TheAdvised
: private advice::Request<int>
{
public:
TheAdvised (Literal topic =0)
{
rebind (topic);
}
void
rebind (Literal topic)
{
defineBinding (topic);
}
bool
got(int val)
{
return val == getAdvice();
}
};
class TheAdvisor
{
advice::Provision<int> link_;
public:
TheAdvisor (Literal topic =0)
{
rebind (topic);
}
void
rebind (Literal topic)
{
link_.defineBinding (topic);
}
void
publish (int val)
{
link_.setAdvice (val);
}
void
clear()
{
link_.retractAdvice();
}
};
}
/***************************************************************************//**
* @test proof-of-concept for the Advice collaboration.
* Advice allows data exchange without coupling the participants tightly.
* This test demonstrates the basic expected behaviour in a simple but
* typical situation: two unrelated entities exchange a piece of data
* just by referring to a symbolic topic ID.
*
* @see advice.hpp
* @see AdviceSituations_test
* @see AdviceMultiplicity_test
* @see AdviceConfiguration_test
* @see AdviceBindingPattern_test
* @see AdviceIndex_test implementation test
*/
class AdviceBasics_test : public Test
{
virtual void
run (Arg)
{
seedRand();
simpleExchange();
createCollaboration();
overwriting_and_retracting();
}
/** @test the very basic usage situation: the advisor sets an information value
* and the advised entity picks it up. */
void
simpleExchange()
{
TheAdvised client; // implicitly opens an request-for-advice
CHECK (client.got (0)); // no advice yet --> getting the default int()
TheAdvisor server; // implicitly prepares an advice provision
CHECK (client.got (0)); // but as no advice was provided yet, nothing happens
int rr{ 1 + rani(1000)};
server.publish (rr); // now an match is detected, creating an advice channel
CHECK (client.got (rr)); // ..so the client can pick up the provided advice value
}
/** @test multiple ways how to initiate the advice collaboration */
void
createCollaboration()
{
TheAdvised client1 ("topic1()");
TheAdvisor server2 ("topic2()");
int r1{ 1 + rani(1000)};
int r2{ 1 + rani(1000)};
server2.publish (r2);
CHECK (client1.got(0));
TheAdvised client2 ("topic2()");
CHECK (client2.got(r2));
TheAdvisor server1;
CHECK (client1.got(0));
server1.publish (r1);
CHECK (client1.got(0));
CHECK (client2.got(r2));
server1.rebind ("topic1()");
CHECK (client1.got(r1));
CHECK (client2.got(r2));
}
/** @test changing the provided advice, finally retracting it,
* causing fallback on the default value. Any given advisor
* can connect to the advice system with multiple bindings
* consecutively. The connection has no identity beside this
* binding, so another server (advisor) can step into an
* existing connection and overwrite or retract the advice.
* Unless retracted, advice remains in the system,
* even after the advisor is gone.
*/
void
overwriting_and_retracting()
{
TheAdvised client1 ("slot1");
TheAdvised client2 ("slot2");
CHECK (client1.got(0));
CHECK (client2.got(0));
int r1{ 1 + rani(1000)};
int r2{ 1 + rani(1000)};
{
TheAdvisor server("slot1()");
CHECK (client1.got(0));
CHECK (client2.got(0));
server.publish (r1);
CHECK (client1.got(r1));
CHECK (client2.got(0));
server.publish (r2);
CHECK (client1.got(r2));
CHECK (client2.got(0));
server.rebind("slot2()");
CHECK (client1.got(0));
CHECK (client2.got(r2));
}
CHECK (client1.got(0));
CHECK (client2.got(r2));
{
TheAdvisor anotherServer("slot1");
CHECK (client1.got(0));
CHECK (client2.got(r2));
anotherServer.publish (r1);
CHECK (client1.got(r1));
CHECK (client2.got(r2));
}
CHECK (client1.got(r1));
CHECK (client2.got(r2));
{
TheAdvisor yetAnotherServer("slot2");
CHECK (client1.got(r1));
CHECK (client2.got(r2));
yetAnotherServer.publish (r1);
CHECK (client1.got(r1));
CHECK (client2.got(r1));
yetAnotherServer.rebind("slot1");
CHECK (client1.got(r1));
CHECK (client2.got(r2)); // ideally it should be 0, but actually we uncover the old provision
// the decision was to err for a simple implementation /////////TICKET #623
yetAnotherServer.clear();
CHECK (client1.got(r1)); // should be 0, but again the existing provision is uncovered
CHECK (client2.got(r2)); // should be 0
yetAnotherServer.rebind("slot2"); // no effect, because it doesn't provide advice anymore
CHECK (client1.got(r1));
CHECK (client2.got(r2));
yetAnotherServer.publish (5);
CHECK (client1.got(r1));
CHECK (client2.got(5));
}
CHECK (client1.got(r1));
CHECK (client2.got(5));
client1.rebind("slot2");
CHECK (client1.got(5));
CHECK (client2.got(5));
client2.rebind("nonExistingSlot");
CHECK (client1.got(5));
CHECK (client2.got(0));
}
};
/** Register this test class... */
LAUNCHER (AdviceBasics_test, "unit common");
}}} // namespace lumiera::advice::test