LUMIERA.clone/tests/core/proc/mobject/session/query-focus-test.cpp
Ichthyostega 28d18a7326 refactoring: better name for the query focus shifting operation
previously this operation was named 'attach', which an be confused
with attching an object to this location. Indeed, the session interface
even offers such an attach function. By renaming the focus moving
operation into QueryFocus::shift(Scope), this ambiguity is resolved
2015-01-08 15:13:27 +01:00

184 lines
6.1 KiB
C++

/*
QueryFocus(Test) - verify proper management of current scope
Copyright (C) Lumiera.org
2009, 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 "proc/mobject/session/test-scopes.hpp"
#include "proc/mobject/session/placement-index.hpp"
#include "proc/mobject/session/query-focus.hpp"
#include "proc/mobject/session/scope.hpp"
#include <iostream>
#include <string>
namespace proc {
namespace mobject {
namespace session {
namespace test {
namespace {
/** Helper: extract the refcount
* of the current path referred by the given focus
*/
inline size_t
refs (QueryFocus const& focus)
{
return focus.currentPath().ref_count();
}
}
using std::string;
using std::cout;
using std::endl;
/*******************************************************************************//**
* @test handling of current query focus when navigating a system of nested scopes.
* Using a pseudo-session (actually just a PlacementIndex), this test
* accesses some nested scopes and then checks moving the "current scope".
* Moreover a (stack-like) sub-focus is created, temporarily moving aside
* the current focus and returning later on.
*
* @see mobject::PlacementIndex
* @see mobject::session::ScopePath
* @see mobject::session::QueryFocus
*/
class QueryFocus_test
: public Test
{
virtual void
run (Arg)
{
// Prepare a (test)Session with
// some nested dummy placements
PPIdx index = build_testScopes();
PMO& root = index->getRoot();
QueryFocus theFocus;
theFocus.reset();
CHECK (Scope(root) == Scope(theFocus));
checkNavigation (theFocus);
Scope scopePosition = Scope(theFocus);
manipulate_subFocus();
QueryFocus currentFocus;
CHECK (scopePosition == Scope(currentFocus));
CHECK (currentFocus == theFocus);
CHECK (2 == refs(currentFocus));
CHECK (2 == refs(theFocus));
}
/** @test move the current focus to different locations
* and discover contents there. */
void
checkNavigation (QueryFocus& focus)
{
focus.reset();
CHECK (Scope(focus).isRoot());
PMO& someObj = *focus.query<TestSubMO1>();
// by construction of the test fixture,
// we know this object is root -> ps2 -> ps3
CHECK (Scope(focus).isRoot());
focus.shift (someObj);
CHECK (!Scope(focus).isRoot());
ScopePath path = focus.currentPath();
CHECK (someObj == path.getLeaf());
CHECK (Scope(focus).getParent().getParent().isRoot());
focus.shift (path.getLeaf().getParent());
CHECK (Scope(focus) == path.getLeaf().getParent());
CHECK (someObj != Scope(focus));
CHECK (path.contains (focus.currentPath()));
CHECK (focus.currentPath().getLeaf().getParent().isRoot());
// as the focus now has been moved up one level,
// we'll re-discover the original starting point as immediate child
CHECK (someObj == *focus.explore<TestSubMO1>());
}
/** @test side-effect free manipulation of a sub-focus,
* while the original focus is pushed aside (stack) */
void
manipulate_subFocus()
{
QueryFocus original; // automatically attaches to current stack top
uint num_refs = refs (original);
CHECK (num_refs > 1); // because the run() function also holds a ref
QueryFocus subF = QueryFocus::push();
cout << string(subF) << endl;
CHECK (subF == original);
CHECK ( 1 == refs(subF) );
CHECK (num_refs == refs(original));
{ // temporarily creating an independent focus attached differently
QueryFocus subF2 = QueryFocus::push(Scope(subF).getParent());
CHECK (subF2 != subF);
CHECK (subF == original);
cout << string(subF2) << endl;
ScopeQuery<TestSubMO21>::iterator ii = subF2.explore<TestSubMO21>();
while (ii) // drill down depth first
{
subF2.shift(*ii);
cout << string(subF2) << endl;
ii = subF2.explore<TestSubMO21>();
}
cout << string(subF2) << "<<<--discovery exhausted" << endl;
subF2.pop(); // releasing this focus and re-attaching to what's on stack top
cout << string(subF2) << "<<<--after pop()" << endl;
CHECK (subF2 == subF);
CHECK (2 == refs(subF2)); // both are now attached to the same path
CHECK (2 == refs(subF));
}
// subF2 went out of scope, but no auto-pop happens (because subF is still there)
cout << string(subF) << endl;
CHECK ( 1 == refs(subF));
CHECK (num_refs == refs(original));
// when subF goes out of scope now, auto-pop will happen...
}
};
/** Register this test class... */
LAUNCHER (QueryFocus_test, "unit session");
}}}} // namespace proc::mobject::session::test