LUMIERA.clone/tests/components/proc/mobject/builder/model-port-registry-test.cpp

275 lines
9.7 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
ModelPortRegistry(Test) - verify handling of model ports
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.
* *****************************************************/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "proc/mobject/builder/model-port-registry.hpp"
#include "proc/asset/timeline.hpp"
#include "proc/asset/pipe.hpp"
#include "lib/query.hpp"
#include "lib/util.hpp"
namespace mobject {
namespace builder {
namespace test {
using util::isSameObject;
using util::isnil;
using asset::Pipe;
using asset::PPipe;
using asset::Struct;
using asset::Timeline;
using asset::PTimeline;
using lumiera::Query;
typedef asset::ID<Pipe> PID;
typedef asset::ID<Struct> TID;
typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
namespace { // test environment
inline PID
getPipe (string id)
{
return Pipe::query("id("+id+")");
}
inline TID
getTimeline (string id)
{
return asset::Struct::retrieve (Query<Timeline> ("id("+id+")"))->getID();
}
struct TestContext
{
ModelPortRegistry registry_;
ModelPortRegistry* previous_;
/** setup */
TestContext()
: registry_()
, previous_(ModelPortRegistry::setActiveInstance (registry_))
{ }
/** tear-down */
~TestContext()
{
if (previous_)
ModelPortRegistry::setActiveInstance (*previous_);
else
ModelPortRegistry::shutdown();
}
};
}
/*********************************************************************************
* @test create a standalone model port registry to verify the behaviour of
* model ports, accessed through reference handles. This test provides an
* example setup detached from the real usage situation within the builder.
* The ModelPortRegistry management interface is used to create and track a
* set of model ports, to be made visible by an atomic, transactional switch.
* The access for client code through the ModelPort frontend is then verified.
*
* @see mobject::ModelPort
* @see mobject::builder::ModelPortRegistry
*/
class ModelPortRegistry_test : public Test
{
virtual void
run (Arg)
{
TestContext ctx;
fabricating_ModelPorts (ctx.registry_);
accessing_ModelPorts();
transactionalSwitch (ctx.registry_);
}
void
fabricating_ModelPorts (ModelPortRegistry& registry)
{
/* == some Assets to play with == */
PID pipeA = getPipe ("pipeA");
PID pipeB = getPipe ("pipeB");
TID someTimeline = getTimeline ("some_test_Timeline");
// start out with defining some new model ports......
MPDescriptor p1 = registry.definePort (pipeA, someTimeline);
MPDescriptor p2 = registry.definePort (pipeB, someTimeline);
CHECK (registry.contains (pipeA));
CHECK (registry.contains (pipeB));
VERIFY_ERROR (DUPLICATE_MODEL_PORT, registry.definePort(pipeB, someTimeline) );
CHECK (registry.contains (pipeB));
CHECK (pipeA == p1.id());
CHECK (pipeB == p2.id());
CHECK (someTimeline == p1.holder());
CHECK (someTimeline == p2.holder());
registry.commit();
}
void
accessing_ModelPorts ()
{
PID pipeA = getPipe ("pipeA");
PID pipeB = getPipe ("pipeB");
PID pipeWC = getPipe ("WCpipe");
ModelPort mp1(pipeA);
ModelPort mp2(pipeB);
VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort unbefitting(pipeWC) );
ModelPort mp1x(pipeA); // can be created multiple times
ModelPort mp2x(mp1x); // can be copied at will
ModelPort mpNull; // can be default constructed (->unconnected)
CHECK (mp1);
CHECK (mp2);
CHECK (mp1x);
CHECK (!mpNull); // bool check verifies setup and connected state
CHECK ( ModelPort::exists (pipeA)); // this is the same check, but invoked just with an pipe-ID
CHECK ( ModelPort::exists (pipeB));
CHECK (!ModelPort::exists (pipeWC));
CHECK (mp1 == mp1x);
CHECK (!isSameObject (mp1, mp1x));
CHECK (mp1 != mp2);
CHECK (mp2 != mp1);
CHECK (mp1 != mpNull);
CHECK (mp2 != mpNull);
CHECK (mp1.pipe() == pipeA);
CHECK (mp2.pipe() == pipeB);
CHECK (mp1x.pipe() == pipeA);
VERIFY_ERROR (UNCONNECTED_MODEL_PORT, mpNull.pipe()); // any further operations on an unconnected port will throw
VERIFY_ERROR (UNCONNECTED_MODEL_PORT, mpNull.holder());
CHECK (mp1.streamType() == pipeA.streamType());
}
void
transactionalSwitch (ModelPortRegistry& registry)
{
PID pipeA = getPipe ("pipeA");
PID pipeB = getPipe ("pipeB");
PID pipeWC = getPipe ("WCpipe");
CHECK ( ModelPort::exists (pipeB));
CHECK (!ModelPort::exists (pipeWC));
CHECK (ModelPort::exists (pipeA));
CHECK (registry.contains (pipeA));
registry.remove (pipeA);
CHECK (!registry.contains (pipeA)); // removed from the current (pending) transaction
CHECK ( ModelPort::exists (pipeA)); // but not yet publicly visible
// now create a new and differing definition of port A
TID anotherTimeline = getTimeline ("another_test_Timeline");
MPDescriptor p1 = registry.definePort (pipeA, anotherTimeline);
CHECK (registry.contains (pipeA));
CHECK (anotherTimeline == p1.holder());
CHECK (ModelPort(pipeA).holder() != anotherTimeline);
registry.remove (pipeB); // some more wired definitions
registry.definePort (pipeWC, anotherTimeline);
CHECK (!registry.contains (pipeB));
CHECK ( registry.contains (pipeWC));
CHECK ( ModelPort::exists (pipeB));
CHECK (!ModelPort::exists (pipeWC));
CHECK ( registry.isRegistered (pipeB)); // this is the same as ModelPort::exists
CHECK (!registry.isRegistered (pipeWC)); //
// Note: pending transaction not yet committed
ModelPort portA(pipeA); // ...... thus the changes aren't reflected to client code
ModelPort portB(pipeB);
VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort ineptly(pipeWC));
CHECK (portA);
CHECK (portB);
CHECK (portA.pipe() == pipeA);
CHECK (portB.pipe() == pipeB);
CHECK (portA.holder() != anotherTimeline);
registry.commit();
CHECK ( ModelPort::exists (pipeA)); // now all our changes got publicly visible
CHECK (!ModelPort::exists (pipeB));
CHECK ( ModelPort::exists (pipeWC));
CHECK ( portA);
CHECK (!portB);
CHECK (portA.holder() == anotherTimeline);
CHECK (portA.pipe() == pipeA);
VERIFY_ERROR (INVALID_MODEL_PORT, portB.pipe());
ModelPort pwc(pipeWC); // now clients may also use the now officially promoted new port
CHECK (pwc);
CHECK (pwc.pipe() == pipeWC);
CHECK (pwc.holder() == anotherTimeline);
// Next: doing several changes,
// but finally *not* committing them...
CHECK ( registry.contains (pipeA));
CHECK (!registry.contains (pipeB));
CHECK ( registry.contains (pipeWC));
registry.remove (pipeA);
registry.clear(); // remove everything from the pending transaction
CHECK (!registry.contains (pipeA));
CHECK (!registry.contains (pipeB));
CHECK (!registry.contains (pipeWC));
registry.definePort (pipeB, anotherTimeline);
CHECK ( registry.contains (pipeB));
CHECK (!portB); // not committed and thus not visible
CHECK (portA);
CHECK (pwc);
registry.rollback();
CHECK ( registry.contains (pipeA)); // no effect to the officialy visible state
CHECK (!registry.contains (pipeB));
CHECK ( registry.contains (pipeWC));
VERIFY_ERROR(INVALID_MODEL_PORT, registry.get(pipeB) );
CHECK (!portB);
}
};
/** Register this test class... */
LAUNCHER (ModelPortRegistry_test, "unit session builder");
}}} // namespace mobject::builder::test