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)
5  2009, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
19 #include "lib/test/run.hpp"
20 #include "lib/test/test-helper.hpp"
25 #include "lib/format-cout.hpp"
26 #include "lib/util.hpp"
27 
28 #include <string>
29 
30 
31 namespace steam {
32 namespace mobject {
33 namespace session {
34 namespace test {
35 
36  using std::string;
37  using util::isnil;
38  using util::isSameObject;
39 
40  using LERR_(LOGIC);
41  using LERR_(INVALID_SCOPE);
42  using LERR_(NOT_IN_SESSION);
43  using LERR_(EMPTY_SCOPE_PATH);
44 
45 
46 
47  /***********************************************************************/
58  class ScopePath_test : public Test
59  {
60 
61  virtual void
62  run (Arg)
63  {
64  // Prepare an (test)Index backing the PlacementRefs
65  PPIdx index = build_testScopes();
66  PMO& startPlacement = retrieve_startElm();
67  CHECK (startPlacement.isValid());
68 
69  checkInvalidScopeDetection();
70  ScopePath testPath = buildPath (startPlacement);
71  checkRelations (testPath,startPlacement);
72  invalidPath (testPath,startPlacement);
73  rootPath (testPath);
74  check_Identity_and_Copy (startPlacement);
75  check_RefcountProtection (startPlacement);
76  navigate (testPath, index);
77  clear (testPath, index);
78  }
79 
80 
81  ScopePath
82  buildPath (PMO& startPla)
83  {
84  Scope startScope (startPla);
85  ScopePath path (startScope);
86  ScopePath path2 (startScope);
87  ScopePath path3 (path2);
88 
89  CHECK (path);
90  CHECK (path.contains (startScope));
91  CHECK ( path.getLeaf() == path2.getLeaf());
92  CHECK (path2.getLeaf() == path3.getLeaf());
93 
94  return path;
95  }
96 
97 
98  void
99  checkInvalidScopeDetection()
100  {
101  // verify detection of illegal scopes and paths...
102  TestPlacement<> notRelated2anything (*new DummyMO);
103  VERIFY_ERROR (NOT_IN_SESSION, Scope invalid (notRelated2anything) );
104 
105  Scope const& scopeOfEvil = fabricate_invalidScope();
106  CHECK (!scopeOfEvil.isValid());
107 
108  VERIFY_ERROR (INVALID_SCOPE, ScopePath outsideCurrentModel (scopeOfEvil) );
109 
110  // but there is one exception to this rule...
111  ScopePath theInvalidToken (Scope::INVALID);
112  CHECK (!theInvalidToken.isValid());
113  CHECK (theInvalidToken.empty());
114  }
115 
116 
117 
118  void
119  checkIteration (ScopePath path, PMO& refPlacement)
120  {
121  Scope refScope(refPlacement);
122  ScopePath::iterator ii = path.begin();
123  CHECK (ii);
124  while (++ii)
125  {
126  CHECK (*ii == refScope.getParent());
127  refScope = *ii;
128  }
129  }
130 
131 
132  void
133  checkRelations (ScopePath path1, PMO& refPlacement)
134  {
135  CHECK (path1.contains (refPlacement));
136 
137  Scope refScope (refPlacement);
138  CHECK (path1.contains (refScope));
139  CHECK (path1.endsAt (refScope));
140 
141  ScopePath path2 (refScope);
142  CHECK (path2.contains (refScope));
143  CHECK (path2.endsAt (refScope));
144 
145  CHECK (path1 == path2);
146  CHECK (!isSameObject (path1,path2));
147 
148  Scope parent = path2.moveUp();
149  CHECK (path2.endsAt (parent));
150  CHECK (path1.endsAt (refScope));
151  CHECK (parent == refScope.getParent());
152  CHECK (path1 != path2);
153  CHECK (path2 != path1);
154  CHECK (path1.contains (path2));
155  CHECK (!disjoint(path1,path2));
156  CHECK (path2 == commonPrefix(path1,path2));
157  CHECK (path2 == commonPrefix(path2,path1));
158  CHECK (path1 != commonPrefix(path1,path2));
159  CHECK (path1 != commonPrefix(path2,path1));
160  }
161 
162 
163  void
164  rootPath (ScopePath refPath)
165  {
166  CHECK ( refPath);
167  refPath.goRoot();
168  CHECK (!refPath);
169  CHECK (!refPath.empty());
170  CHECK (!refPath.isValid());
171  CHECK (1 == refPath.length());
172 
173  ScopePath defaultPath;
174  CHECK (!defaultPath);
175  CHECK (refPath == defaultPath);
176  }
177 
178 
179  void
180  invalidPath (ScopePath refPath, PMO& refPlacement)
181  {
182  CHECK (refPath);
183  CHECK (!ScopePath::INVALID);
184  CHECK (isnil (ScopePath::INVALID));
185  CHECK ("!" == string(ScopePath::INVALID));
186 
187  ScopePath invalidP (ScopePath::INVALID);
188  CHECK (isnil (invalidP));
189  CHECK (invalidP == ScopePath::INVALID);
190  CHECK (!isSameObject (invalidP, ScopePath::INVALID));
191 
192  CHECK (refPath.contains (refPlacement));
193  CHECK (!invalidP.contains (refPlacement));
194 
195  Scope refScope (refPlacement);
196  CHECK (!invalidP.contains (refScope));
197  VERIFY_ERROR (EMPTY_SCOPE_PATH, invalidP.endsAt (refScope) ); // Logic: can't inspect the end of nothing
198 
199  CHECK (refPath.contains (invalidP)); // If the moon is made of green cheese, I'll eat my hat!
200  CHECK (!invalidP.contains (refPath));
201  CHECK (invalidP == commonPrefix(refPath,invalidP));
202  CHECK (invalidP == commonPrefix(invalidP,refPath));
203 
204  VERIFY_ERROR (EMPTY_SCOPE_PATH, invalidP.moveUp() );
205  Scope root = refPath.goRoot();
206  CHECK (1 == refPath.length());
207 
208  Scope const& nil = refPath.moveUp();
209  CHECK (refPath.empty());
210  CHECK (!nil.isValid());
211  CHECK (refPath == invalidP);
212  CHECK (invalidP.contains (nil));
213  CHECK (invalidP.contains (refPath));
214  CHECK (!invalidP.contains (refScope));
215 
216  VERIFY_ERROR (EMPTY_SCOPE_PATH, refPath.navigate(root) );
217 
218  //ScopePath::INVALID.navigate(root); // doesn't compile: INVALID is immutable
219  }
220 
221 
222  void
223  check_Identity_and_Copy (PMO& refPlacement)
224  {
225  Scope startScope (refPlacement);
226  ScopePath path1 (startScope);
227  ScopePath path2 (startScope);
228  ScopePath path3 (path2);
229 
230  CHECK (path1.contains (startScope));
231  CHECK (path2.contains (startScope));
232  CHECK (path3.contains (startScope));
233 
234  CHECK (path1 == path2);
235  CHECK (path2 == path3);
236  CHECK (path1 == path3);
237  CHECK (!isSameObject (path1,path2));
238  CHECK (!isSameObject (path2,path3));
239  CHECK (!isSameObject (path1,path3));
240 
241  Scope parent = path3.moveUp(); // mutation
242  CHECK (parent == path2.getLeaf().getParent());
243 
244  CHECK (path1 == path2); // the others are not affected
245  CHECK (path2 != path3);
246  CHECK (path1 != path3);
247 
248  path2 = path3;
249  CHECK (path1 != path2);
250  CHECK (path2 == path3);
251  CHECK (path1 != path3);
252 
253  path2 = ScopePath::INVALID;
254  CHECK (path1 != path2);
255  CHECK (path2 != path3);
256  CHECK (path1 != path3);
257  }
258 
259 
263  void
265  {
266  Scope startScope (refPlacement);
267  ScopePath path1 (startScope);
268  ScopePath path2 (path1);
269 
270  path1 = path2;
271  CHECK (!isSameObject (path1,path2));
272  CHECK (0 == path1.ref_count());
273  CHECK (0 == path2.ref_count());
274 
275  intrusive_ptr_add_ref (&path2);
276  CHECK (0 == path1.ref_count());
277  CHECK (0 < path2.ref_count());
278 
279  ScopePath path3 (path2);
280  CHECK (0 == path3.ref_count()); // refcount not copied
281 
282  path3.moveUp();
283 
284  VERIFY_ERROR (LOGIC, path2 = path3 ); // overwriting of path with refcount is prohibited
285  CHECK (path1 != path3);
286  path1 = path2; // but path without refcount may be overwritten
287  path1 = path3;
288  CHECK (path1 == path3);
289 
290  intrusive_ptr_release (&path2); // refcount drops to zero...
291  CHECK (0 == path1.ref_count());
292  CHECK (0 == path2.ref_count());
293  }
294 
295 
296 
306  void
307  navigate (const ScopePath refPath, PPIdx index)
308  {
309  #define __SHOWPATH(N) cout << "Step("<<N<<"): "<< path << endl;
310 
311  ScopePath path (refPath); __SHOWPATH(1)
312  CHECK (path == refPath);
313 
314  Scope leaf = path.getLeaf();
315  Scope parent = path.moveUp(); __SHOWPATH(2)
316  CHECK (path != refPath);
317  CHECK (refPath.contains (path));
318  CHECK (refPath.endsAt (leaf));
319  CHECK (path.endsAt (parent));
320  CHECK (parent == leaf.getParent());
321  CHECK (parent == path.getLeaf());
322 
323  Scope root = path.goRoot(); __SHOWPATH(3)
324  CHECK (path != refPath);
325  CHECK (path.endsAt (root));
326  CHECK (refPath.contains (path));
327  CHECK (!path.endsAt (parent));
328  CHECK (!path.endsAt (leaf));
329 
330  path.navigate (parent); __SHOWPATH(4)
331  CHECK (path.endsAt (parent));
332  CHECK (!path.endsAt (root));
333  CHECK (!path.endsAt (leaf));
334 
335  TestPlacement<> newNode (*new DummyMO);
336  PMO& parentRefPoint = parent.getTop();
337  Scope newLocation =
338  index->find( // place newNode as sibling of "leaf"
339  index->insert (newNode, parentRefPoint));
340  path.navigate (newLocation); __SHOWPATH(5)
341  Scope sibling = path.getLeaf();
342  CHECK (sibling == newLocation);
343  CHECK (parent == sibling.getParent());
344  CHECK (path.endsAt (sibling));
345  CHECK (path.contains (parent));
346  CHECK (path.contains (root));
347  CHECK (!refPath.contains (path));
348  CHECK (!path.contains (refPath));
349  CHECK (!disjoint (path,refPath));
350  CHECK (!disjoint (refPath,path));
351 
352  ScopePath prefix = commonPrefix (path,refPath);
353  CHECK (prefix == commonPrefix (refPath,path));
354  CHECK (prefix.endsAt (parent));
355  CHECK (!prefix.contains (leaf));
356  CHECK (!prefix.contains (sibling));
357  path.navigate (prefix.getLeaf()); __SHOWPATH(6)
358  CHECK (path == prefix);
359 
360  // try to navigate to an unconnected location...
361  ScopePath beforeInvalidNavigation = path;
362  Scope const& unrelatedScope (fabricate_invalidScope());
363  VERIFY_ERROR (INVALID_SCOPE, path.navigate (unrelatedScope) );
364  CHECK (path == beforeInvalidNavigation); // not messed up by the incident
365 
366  // now explore a completely separate branch....
367  PMO& separatePlacement = *explore_testScope (
369  retrieve_firstTestSubMO21()));
370  path.navigate (separatePlacement);
371  CHECK (path);
372  CHECK (disjoint (path,refPath));
373  CHECK (path.contains(separatePlacement));
374  Scope other = path.getLeaf();
375  CHECK (isSameObject (other.getTop(), separatePlacement));
376  ScopePath rootPrefix = commonPrefix (path,refPath);
377  CHECK (rootPrefix.endsAt (root));
378  }
379 
380 
381 
382  void
383  clear (ScopePath& path, PPIdx index)
384  {
385  CHECK (path);
386  PMO& rootNode = index->getRoot();
387  CHECK (path.getLeaf() != rootNode);
388 
389  path.clear();
390  CHECK (!path);
391  CHECK (!isnil (path));
392  CHECK (path.getLeaf() == rootNode);
393  }
394  };
395 
396 
397 
399  LAUNCHER (ScopePath_test, "unit session");
400 
401 
402 }}}} // 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:209
Definition: run.hpp:40
bool endsAt(Scope const &) const
verify the scope in question is equivalent to our leaf scope.
Definition: scope-path.cpp:203
bool empty() const
an empty path doesn&#39;t even contain a root element.
Definition: scope-path.hpp:256
static const ScopePath INVALID
constant invalid path token.
Definition: scope-path.hpp:144
PPIdx build_testScopes()
helper for tests: create a pseudo-session (actually just a PlacementIndex), which contains some neste...
Definition: test-scopes.cpp:38
void intrusive_ptr_add_ref(ScopePath *pathFrame)
management function for boost::intrusive_ptr to be picked up by ADL
Definition: scope-path.hpp:215
#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:65
Sequence of nested scopes within the high-level model.
Definition: scope-path.hpp:126
A Placement scope within the high-level-model.
Definition: scope.hpp:69
bool isValid() const
check if this scope can be located.
Definition: scope.cpp:231
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:87
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.
Simplistic 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:161
static const Scope INVALID
constant invalid scope token.
Definition: scope.hpp:83
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, based directly on the referee&#39;s memory identities. ...
Definition: util.hpp:421