Lumiera  0.pre.03
»edit your freedom«
scope-path-test.cpp
Go to the documentation of this file.
1 /*
2  ScopePath(Test) - verify handling of logical access path down from Session root
3 
4  Copyright (C) Lumiera.org
5  2009, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
28 #include "lib/test/run.hpp"
29 #include "lib/test/test-helper.hpp"
34 #include "lib/format-cout.hpp"
35 #include "lib/util.hpp"
36 
37 #include <string>
38 
39 
40 namespace steam {
41 namespace mobject {
42 namespace session {
43 namespace test {
44 
45  using std::string;
46  using util::isnil;
47  using util::isSameObject;
48 
49  using LERR_(LOGIC);
50  using LERR_(INVALID_SCOPE);
51  using LERR_(NOT_IN_SESSION);
52  using LERR_(EMPTY_SCOPE_PATH);
53 
54 
55 
56  /***********************************************************************/
67  class ScopePath_test : public Test
68  {
69 
70  virtual void
71  run (Arg)
72  {
73  // Prepare an (test)Index backing the PlacementRefs
74  PPIdx index = build_testScopes();
75  PMO& startPlacement = retrieve_startElm();
76  CHECK (startPlacement.isValid());
77 
78  checkInvalidScopeDetection();
79  ScopePath testPath = buildPath (startPlacement);
80  checkRelations (testPath,startPlacement);
81  invalidPath (testPath,startPlacement);
82  rootPath (testPath);
83  check_Identity_and_Copy (startPlacement);
84  check_RefcountProtection (startPlacement);
85  navigate (testPath, index);
86  clear (testPath, index);
87  }
88 
89 
90  ScopePath
91  buildPath (PMO& startPla)
92  {
93  Scope startScope (startPla);
94  ScopePath path (startScope);
95  ScopePath path2 (startScope);
96  ScopePath path3 (path2);
97 
98  CHECK (path);
99  CHECK (path.contains (startScope));
100  CHECK ( path.getLeaf() == path2.getLeaf());
101  CHECK (path2.getLeaf() == path3.getLeaf());
102 
103  return path;
104  }
105 
106 
107  void
108  checkInvalidScopeDetection()
109  {
110  // verify detection of illegal scopes and paths...
111  TestPlacement<> notRelated2anything (*new DummyMO);
112  VERIFY_ERROR (NOT_IN_SESSION, Scope invalid (notRelated2anything) );
113 
114  Scope const& scopeOfEvil = fabricate_invalidScope();
115  CHECK (!scopeOfEvil.isValid());
116 
117  VERIFY_ERROR (INVALID_SCOPE, ScopePath outsideCurrentModel (scopeOfEvil) );
118 
119  // but there is one exception to this rule...
120  ScopePath theInvalidToken (Scope::INVALID);
121  CHECK (!theInvalidToken.isValid());
122  CHECK (theInvalidToken.empty());
123  }
124 
125 
126 
127  void
128  checkIteration (ScopePath path, PMO& refPlacement)
129  {
130  Scope refScope(refPlacement);
131  ScopePath::iterator ii = path.begin();
132  CHECK (ii);
133  while (++ii)
134  {
135  CHECK (*ii == refScope.getParent());
136  refScope = *ii;
137  }
138  }
139 
140 
141  void
142  checkRelations (ScopePath path1, PMO& refPlacement)
143  {
144  CHECK (path1.contains (refPlacement));
145 
146  Scope refScope (refPlacement);
147  CHECK (path1.contains (refScope));
148  CHECK (path1.endsAt (refScope));
149 
150  ScopePath path2 (refScope);
151  CHECK (path2.contains (refScope));
152  CHECK (path2.endsAt (refScope));
153 
154  CHECK (path1 == path2);
155  CHECK (!isSameObject (path1,path2));
156 
157  Scope parent = path2.moveUp();
158  CHECK (path2.endsAt (parent));
159  CHECK (path1.endsAt (refScope));
160  CHECK (parent == refScope.getParent());
161  CHECK (path1 != path2);
162  CHECK (path2 != path1);
163  CHECK (path1.contains (path2));
164  CHECK (!disjoint(path1,path2));
165  CHECK (path2 == commonPrefix(path1,path2));
166  CHECK (path2 == commonPrefix(path2,path1));
167  CHECK (path1 != commonPrefix(path1,path2));
168  CHECK (path1 != commonPrefix(path2,path1));
169  }
170 
171 
172  void
173  rootPath (ScopePath refPath)
174  {
175  CHECK ( refPath);
176  refPath.goRoot();
177  CHECK (!refPath);
178  CHECK (!refPath.empty());
179  CHECK (!refPath.isValid());
180  CHECK (1 == refPath.length());
181 
182  ScopePath defaultPath;
183  CHECK (!defaultPath);
184  CHECK (refPath == defaultPath);
185  }
186 
187 
188  void
189  invalidPath (ScopePath refPath, PMO& refPlacement)
190  {
191  CHECK (refPath);
192  CHECK (!ScopePath::INVALID);
193  CHECK (isnil (ScopePath::INVALID));
194  CHECK ("!" == string(ScopePath::INVALID));
195 
196  ScopePath invalidP (ScopePath::INVALID);
197  CHECK (isnil (invalidP));
198  CHECK (invalidP == ScopePath::INVALID);
199  CHECK (!isSameObject (invalidP, ScopePath::INVALID));
200 
201  CHECK (refPath.contains (refPlacement));
202  CHECK (!invalidP.contains (refPlacement));
203 
204  Scope refScope (refPlacement);
205  CHECK (!invalidP.contains (refScope));
206  VERIFY_ERROR (EMPTY_SCOPE_PATH, invalidP.endsAt (refScope) ); // Logic: can't inspect the end of nothing
207 
208  CHECK (refPath.contains (invalidP)); // If the moon is made of green cheese, I'll eat my hat!
209  CHECK (!invalidP.contains (refPath));
210  CHECK (invalidP == commonPrefix(refPath,invalidP));
211  CHECK (invalidP == commonPrefix(invalidP,refPath));
212 
213  VERIFY_ERROR (EMPTY_SCOPE_PATH, invalidP.moveUp() );
214  Scope root = refPath.goRoot();
215  CHECK (1 == refPath.length());
216 
217  Scope const& nil = refPath.moveUp();
218  CHECK (refPath.empty());
219  CHECK (!nil.isValid());
220  CHECK (refPath == invalidP);
221  CHECK (invalidP.contains (nil));
222  CHECK (invalidP.contains (refPath));
223  CHECK (!invalidP.contains (refScope));
224 
225  VERIFY_ERROR (EMPTY_SCOPE_PATH, refPath.navigate(root) );
226 
227  //ScopePath::INVALID.navigate(root); // doesn't compile: INVALID is immutable
228  }
229 
230 
231  void
232  check_Identity_and_Copy (PMO& refPlacement)
233  {
234  Scope startScope (refPlacement);
235  ScopePath path1 (startScope);
236  ScopePath path2 (startScope);
237  ScopePath path3 (path2);
238 
239  CHECK (path1.contains (startScope));
240  CHECK (path2.contains (startScope));
241  CHECK (path3.contains (startScope));
242 
243  CHECK (path1 == path2);
244  CHECK (path2 == path3);
245  CHECK (path1 == path3);
246  CHECK (!isSameObject (path1,path2));
247  CHECK (!isSameObject (path2,path3));
248  CHECK (!isSameObject (path1,path3));
249 
250  Scope parent = path3.moveUp(); // mutation
251  CHECK (parent == path2.getLeaf().getParent());
252 
253  CHECK (path1 == path2); // the others are not affected
254  CHECK (path2 != path3);
255  CHECK (path1 != path3);
256 
257  path2 = path3;
258  CHECK (path1 != path2);
259  CHECK (path2 == path3);
260  CHECK (path1 != path3);
261 
262  path2 = ScopePath::INVALID;
263  CHECK (path1 != path2);
264  CHECK (path2 != path3);
265  CHECK (path1 != path3);
266  }
267 
268 
272  void
274  {
275  Scope startScope (refPlacement);
276  ScopePath path1 (startScope);
277  ScopePath path2 (path1);
278 
279  path1 = path2;
280  CHECK (!isSameObject (path1,path2));
281  CHECK (0 == path1.ref_count());
282  CHECK (0 == path2.ref_count());
283 
284  intrusive_ptr_add_ref (&path2);
285  CHECK (0 == path1.ref_count());
286  CHECK (0 < path2.ref_count());
287 
288  ScopePath path3 (path2);
289  CHECK (0 == path3.ref_count()); // refcount not copied
290 
291  path3.moveUp();
292 
293  VERIFY_ERROR (LOGIC, path2 = path3 ); // overwriting of path with refcount is prohibited
294  CHECK (path1 != path3);
295  path1 = path2; // but path without refcount may be overwritten
296  path1 = path3;
297  CHECK (path1 == path3);
298 
299  intrusive_ptr_release (&path2); // refcount drops to zero...
300  CHECK (0 == path1.ref_count());
301  CHECK (0 == path2.ref_count());
302  }
303 
304 
305 
315  void
316  navigate (const ScopePath refPath, PPIdx index)
317  {
318  #define __SHOWPATH(N) cout << "Step("<<N<<"): "<< path << endl;
319 
320  ScopePath path (refPath); __SHOWPATH(1)
321  CHECK (path == refPath);
322 
323  Scope leaf = path.getLeaf();
324  Scope parent = path.moveUp(); __SHOWPATH(2)
325  CHECK (path != refPath);
326  CHECK (refPath.contains (path));
327  CHECK (refPath.endsAt (leaf));
328  CHECK (path.endsAt (parent));
329  CHECK (parent == leaf.getParent());
330  CHECK (parent == path.getLeaf());
331 
332  Scope root = path.goRoot(); __SHOWPATH(3)
333  CHECK (path != refPath);
334  CHECK (path.endsAt (root));
335  CHECK (refPath.contains (path));
336  CHECK (!path.endsAt (parent));
337  CHECK (!path.endsAt (leaf));
338 
339  path.navigate (parent); __SHOWPATH(4)
340  CHECK (path.endsAt (parent));
341  CHECK (!path.endsAt (root));
342  CHECK (!path.endsAt (leaf));
343 
344  TestPlacement<> newNode (*new DummyMO);
345  PMO& parentRefPoint = parent.getTop();
346  Scope newLocation =
347  index->find( // place newNode as sibling of "leaf"
348  index->insert (newNode, parentRefPoint));
349  path.navigate (newLocation); __SHOWPATH(5)
350  Scope sibling = path.getLeaf();
351  CHECK (sibling == newLocation);
352  CHECK (parent == sibling.getParent());
353  CHECK (path.endsAt (sibling));
354  CHECK (path.contains (parent));
355  CHECK (path.contains (root));
356  CHECK (!refPath.contains (path));
357  CHECK (!path.contains (refPath));
358  CHECK (!disjoint (path,refPath));
359  CHECK (!disjoint (refPath,path));
360 
361  ScopePath prefix = commonPrefix (path,refPath);
362  CHECK (prefix == commonPrefix (refPath,path));
363  CHECK (prefix.endsAt (parent));
364  CHECK (!prefix.contains (leaf));
365  CHECK (!prefix.contains (sibling));
366  path.navigate (prefix.getLeaf()); __SHOWPATH(6)
367  CHECK (path == prefix);
368 
369  // try to navigate to an unconnected location...
370  ScopePath beforeInvalidNavigation = path;
371  Scope const& unrelatedScope (fabricate_invalidScope());
372  VERIFY_ERROR (INVALID_SCOPE, path.navigate (unrelatedScope) );
373  CHECK (path == beforeInvalidNavigation); // not messed up by the incident
374 
375  // now explore a completely separate branch....
376  PMO& separatePlacement = *explore_testScope (
378  retrieve_firstTestSubMO21()));
379  path.navigate (separatePlacement);
380  CHECK (path);
381  CHECK (disjoint (path,refPath));
382  CHECK (path.contains(separatePlacement));
383  Scope other = path.getLeaf();
384  CHECK (isSameObject (other.getTop(), separatePlacement));
385  ScopePath rootPrefix = commonPrefix (path,refPath);
386  CHECK (rootPrefix.endsAt (root));
387  }
388 
389 
390 
391  void
392  clear (ScopePath& path, PPIdx index)
393  {
394  CHECK (path);
395  PMO& rootNode = index->getRoot();
396  CHECK (path.getLeaf() != rootNode);
397 
398  path.clear();
399  CHECK (!path);
400  CHECK (!isnil (path));
401  CHECK (path.getLeaf() == rootNode);
402  }
403  };
404 
405 
406 
408  LAUNCHER (ScopePath_test, "unit session");
409 
410 
411 }}}} // namespace steam::mobject::session::test
Automatically use custom string conversion in C++ stream output.
Unit test helper to generate deliberately wrong placement scopes.
Test MObject subclass, which, contrary to any real MObject, can be created directly without involving...
Scope getParent() const
retrieve the parent scope which encloses this scope.
Definition: scope.cpp:218
Definition: run.hpp:49
bool endsAt(Scope const &) const
verify the scope in question is equivalent to our leaf scope.
Definition: scope-path.cpp:212
bool empty() const
an empty path doesn&#39;t even contain a root element.
Definition: scope-path.hpp:265
static const ScopePath INVALID
constant invalid path token.
Definition: scope-path.hpp:153
PPIdx build_testScopes()
helper for tests: create a pseudo-session (actually just a PlacementIndex), which contains some neste...
Definition: test-scopes.cpp:47
void intrusive_ptr_add_ref(ScopePath *pathFrame)
management function for boost::intrusive_ptr to be picked up by ADL
Definition: scope-path.hpp:224
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Steam-Layer implementation namespace root.
Namespace of Session and user visible high-level objects.
Definition: sequence.hpp:74
Sequence of nested scopes within the high-level model.
Definition: scope-path.hpp:135
A Placement scope within the high-level-model.
Definition: scope.hpp:78
bool isValid() const
check if this scope can be located.
Definition: scope.cpp:240
PlacementMO & retrieve_startElm()
complement to the helper: retrieve one of the dummy placements which is a Placement<> and way down in...
Definition: test-scopes.cpp:96
Unit test helper to generate a system of nested test scopes.
ScopeQuery< MObject >::iterator explore_testScope(PlacementMO const &scopeTop)
shortcut to explore the contents of a scope within the current index.
Core of the session implementation datastructure.
Simple test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
A collection of frequently used helper functions to support unit testing.
void navigate(const ScopePath refPath, PPIdx index)
bool isValid() const
a valid path consists of more than just the root element.
Definition: scope-path.cpp:170
static const Scope INVALID
constant invalid scope token.
Definition: scope.hpp:92
An Object representing a sequence of nested scopes within the Session.
Accessing a STL element range through a Lumiera forward iterator, An instance of this iterator adapte...
bool isSameObject(A const &a, B const &b)
compare plain object identity, bypassing any custom comparison operators.
Definition: util.hpp:372