From 46597009f9ab57ce4a0436fb1ad8b31c2812ca7b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 8 Oct 2010 06:24:25 +0200 Subject: [PATCH] get the basic ScopePath_test to pass --- src/proc/mobject/session/scope-path.cpp | 21 ++-- src/proc/mobject/session/scope-path.hpp | 4 +- src/proc/mobject/session/scope.cpp | 4 + src/proc/mobject/session/scope.hpp | 4 +- tests/43session.tests | 3 +- .../proc/mobject/session/scope-path-test.cpp | 107 ++++++++++++------ 6 files changed, 98 insertions(+), 45 deletions(-) diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp index 40c19cd2d..49ec87b0c 100644 --- a/src/proc/mobject/session/scope-path.cpp +++ b/src/proc/mobject/session/scope-path.cpp @@ -63,8 +63,8 @@ namespace session { { REQUIRE (path); if (path->empty()) - throw error::Invalid (operation_descr+" an empty placement scope path" - , LUMIERA_ERROR_EMPTY_SCOPE_PATH); + throw error::Logic (operation_descr+" an empty placement scope path" + , LUMIERA_ERROR_EMPTY_SCOPE_PATH); } }//(End) helpers @@ -100,7 +100,7 @@ namespace session { : refcount_(0) , path_() { - if (!leaf.isValid()) return; // invalid leaf defines invalid path.... + if (leaf == Scope::INVALID) return; // invalid leaf defines invalid path.... clear(); navigate (leaf); @@ -196,6 +196,8 @@ namespace session { bool ScopePath::contains (Scope const& aScope) const { + if (aScope == Scope::INVALID) return true; // bottom is contained everywhere + for (iterator ii = this->begin(); ii; ++ii) if (aScope == *ii) return true; @@ -207,8 +209,8 @@ namespace session { bool ScopePath::contains (ScopePath const& otherPath) const { - if ( empty()) return false; if (!otherPath.isValid()) return true; + if ( empty()) return false; if (!isValid()) return false; ASSERT (1 < length()); @@ -262,20 +264,19 @@ namespace session { } - Scope& + Scope const& ScopePath::moveUp() { ___check_notBottom (this, "Navigating"); - static Scope invalidScope; path_.resize (length()-1); - if (empty()) return invalidScope; + if (empty()) return Scope::INVALID; else return path_.back(); } - Scope& + Scope const& ScopePath::goRoot() { ___check_notBottom (this, "Navigating"); @@ -290,6 +291,10 @@ namespace session { ScopePath::navigate (Scope const& target) { ___check_notBottom (this, "Navigating"); + if (!target.isValid()) + throw error::Invalid ("can't navigate to a target scope outside the model" + , LUMIERA_ERROR_INVALID_SCOPE); + std::vector otherPath; append_all (discoverScopePath(target), otherPath); reverse (otherPath.begin(), otherPath.end()); diff --git a/src/proc/mobject/session/scope-path.hpp b/src/proc/mobject/session/scope-path.hpp index e0d3792f0..b807e7ea0 100644 --- a/src/proc/mobject/session/scope-path.hpp +++ b/src/proc/mobject/session/scope-path.hpp @@ -187,8 +187,8 @@ namespace session { /* == mutations == */ void clear(); - Scope& moveUp(); - Scope& goRoot(); + Scope const& moveUp(); + Scope const& goRoot(); void navigate (Scope const&); diff --git a/src/proc/mobject/session/scope.cpp b/src/proc/mobject/session/scope.cpp index ee1c9218b..dc86bc2ed 100644 --- a/src/proc/mobject/session/scope.cpp +++ b/src/proc/mobject/session/scope.cpp @@ -91,6 +91,10 @@ namespace session { } + /** constant \em invalid scope token. */ + const Scope Scope::INVALID = Scope(); + + ScopeLocator::ScopeLocator() : focusStack_(new QueryFocusStack) diff --git a/src/proc/mobject/session/scope.hpp b/src/proc/mobject/session/scope.hpp index e7593fc0b..a6e266e6f 100644 --- a/src/proc/mobject/session/scope.hpp +++ b/src/proc/mobject/session/scope.hpp @@ -72,7 +72,9 @@ namespace session { Scope (Scope const&); Scope& operator= (Scope const&); - + + static const Scope INVALID; + static Scope containing (PlacementMO const& aPlacement); static Scope containing (RefPlacement const& refPlacement); diff --git a/tests/43session.tests b/tests/43session.tests index dec155f1d..e70ae0af6 100644 --- a/tests/43session.tests +++ b/tests/43session.tests @@ -164,7 +164,8 @@ PLANNED "Placement search scope" PlacementScope_test < -//#include - namespace mobject { @@ -42,19 +36,44 @@ namespace test { using util::isnil; using util::isSameObject; -//using lumiera::Time; -//using std::string; -//using std::cout; -//using std::endl; -// using namespace mobject::test; + using lumiera::error::LUMIERA_ERROR_LOGIC; using lumiera::error::LUMIERA_ERROR_INVALID; + namespace { // subversive test helper... + + Scope const& + fabricate_invalidScope() + { /** + * assumed to have identical memory layout + * to a Scope object, as the latter is implemented + * by a PlacementRef, which in turn is just an + * encapsulated Placement-ID + */ + struct Ambush + { + /** random ID assumed to be + * nowhere in the model */ + PlacementMO::ID derailed_; + }; + + static Ambush _kinky_; + return *reinterpret_cast (&_kinky_); + } + } + + + + + /*************************************************************************** * @test properties and behaviour of the path of nested scopes. - * Using a pseudo-session (actually just a PlacementIndex), this test - * creates some nested scopes and executes navigation moves on them. + * Using a pseudo-session (actually just a PlacementIndex), + * this test creates some nested scopes, builds scope paths + * and executes various comparisons navigation moves on them. + * Especially detection of invalid scopes and paths and the + * special handling of empty and root paths is covered. * @see mobject::Placement * @see mobject::session::ScopePath * @see mobject::session::QueryFocus @@ -70,6 +89,7 @@ namespace test { PMO& startPlacement = retrieve_startElm(); ASSERT (startPlacement.isValid()); + checkInvalidScopeDetection(); ScopePath testPath = buildPath (startPlacement); checkRelations (testPath,startPlacement); invalidPath (testPath,startPlacement); @@ -95,13 +115,30 @@ namespace test { ASSERT ( path.getLeaf() == path2.getLeaf()); ASSERT (path2.getLeaf() == path3.getLeaf()); - Scope unrelatedScope (TestPlacement<> (*new DummyMO)); - VERIFY_ERROR (INVALID, ScopePath(unrelatedScope) ); - return path; } + void + checkInvalidScopeDetection() + { + // verify detection of illegal scopes and paths... + TestPlacement<> notRelated2anything (*new DummyMO); + VERIFY_ERROR (NOT_IN_SESSION, Scope invalid (notRelated2anything) ); + + Scope const& scopeOfEvil = fabricate_invalidScope(); + REQUIRE (!scopeOfEvil.isValid()); + + VERIFY_ERROR (INVALID_SCOPE, ScopePath outsideCurrentModel (scopeOfEvil) ); + + // but there is one exception to this rule... + ScopePath theInvalidToken (Scope::INVALID); + CHECK (!theInvalidToken.isValid()); + CHECK (theInvalidToken.empty()); + } + + + void checkIteration (ScopePath path, PMO& refPlacement) { @@ -180,28 +217,28 @@ namespace test { Scope refScope (refPlacement); ASSERT (!invalidP.contains (refScope)); - ASSERT (!invalidP.endsAt (refScope)); + VERIFY_ERROR (EMPTY_SCOPE_PATH, invalidP.endsAt (refScope) ); // Logic: can't inspect the end of nothing - ASSERT (refPath.contains (invalidP)); // If the moon is made of green cheese, I'll eat my hat! + ASSERT (refPath.contains (invalidP)); // If the moon is made of green cheese, I'll eat my hat! ASSERT (!invalidP.contains (refPath)); ASSERT (invalidP == commonPrefix(refPath,invalidP)); ASSERT (invalidP == commonPrefix(invalidP,refPath)); - VERIFY_ERROR (LOGIC, invalidP.moveUp()); + VERIFY_ERROR (EMPTY_SCOPE_PATH, invalidP.moveUp() ); Scope root = refPath.goRoot(); ASSERT (1 == refPath.length()); - Scope nil = refPath.moveUp(); + Scope const& nil = refPath.moveUp(); ASSERT (refPath.empty()); ASSERT (!nil.isValid()); ASSERT (refPath == invalidP); ASSERT (invalidP.contains (nil)); + ASSERT (invalidP.contains (refPath)); + ASSERT (!invalidP.contains (refScope)); - refPath.navigate(root); - ASSERT (refPath != invalidP); - ASSERT (!isnil (refPath)); + VERIFY_ERROR (EMPTY_SCOPE_PATH, refPath.navigate(root) ); - //ScopePath::INVALID.navigate(root); // doesn't compile + //ScopePath::INVALID.navigate(root); // doesn't compile: INVALID is immutable } @@ -234,7 +271,7 @@ namespace test { ASSERT (path2 == path3); ASSERT (path1 != path3); - path1 = ScopePath::INVALID; + path2 = ScopePath::INVALID; ASSERT (path1 != path2); ASSERT (path2 != path3); ASSERT (path1 != path3); @@ -285,7 +322,7 @@ namespace test { * - attach a new sibling node and move the path down to there * - extract the common prefix, which should again point to the parent * - find a placement in a completely separate branch (only sharing the - * root node). Navigate to there and verify root is the common prefix. + * root node). Navigate to there and verify root is the common prefix. */ void navigate (const ScopePath refPath, PPIdx index) @@ -316,9 +353,12 @@ namespace test { TestPlacement<> newNode (*new DummyMO); PMO& parentRefPoint = parent.getTop(); - index->insert (newNode, parentRefPoint); // place as sibling of "leaf" - path.navigate (newNode); + Scope newLocation = + index->find( // place newNode as sibling of "leaf" + index->insert (newNode, parentRefPoint)); + path.navigate (newLocation); Scope sibling = path.getLeaf(); + ASSERT (sibling == newLocation); ASSERT (parent == sibling.getParent()); ASSERT (path.endsAt (sibling)); ASSERT (path.contains (parent)); @@ -338,8 +378,8 @@ namespace test { // try to navigate to an unconnected location... ScopePath beforeInvalidNavigation = path; - Scope unrelatedScope (TestPlacement<> (*new DummyMO)); - VERIFY_ERROR (INVALID, path.navigate (unrelatedScope) ); + Scope const& unrelatedScope (fabricate_invalidScope()); + VERIFY_ERROR (INVALID_SCOPE, path.navigate (unrelatedScope) ); ASSERT (path == beforeInvalidNavigation); // not messed up by the incident // now explore a completely separate branch.... @@ -359,11 +399,12 @@ namespace test { } + void clear (ScopePath& path, PPIdx index) { ASSERT (path); - PMO rootNode = index->getRoot(); + PMO& rootNode = index->getRoot(); ASSERT (path.getLeaf() != rootNode); path.clear(); @@ -371,10 +412,10 @@ namespace test { ASSERT (!isnil (path)); ASSERT (path.getLeaf() == rootNode); } - }; + /** Register this test class... */ LAUNCHER (ScopePath_test, "unit session");