Lumiera  0.pre.03
»edit your freedom«
query-focus-stack-test.cpp
Go to the documentation of this file.
1 /*
2  QueryFocusStack(Test) - verify the stack of focus path frames
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"
24 #include "lib/util.hpp"
25 
26 
27 namespace steam {
28 namespace mobject {
29 namespace session {
30 namespace test {
31 
32  using util::isnil;
33  using util::isSameObject;
34  using LERR_(INVALID_SCOPE);
35 
36 
37  /***********************************************************************/
51  class QueryFocusStack_test : public Test
52  {
53 
54  virtual void
55  run (Arg)
56  {
57  // Prepare an (test)Index and
58  // set up dummy session contents
59  PPIdx index = build_testScopes();
60 
61  createStack();
62  usePushedFrame();
63  automaticFrameHandling();
64  verify_errorHandling();
65  clear();
66  }
67 
68 
69  void
70  createStack ()
71  {
72  QueryFocusStack stack;
73 
74  CHECK (!isnil (stack));
75  CHECK (!isnil (stack.top()));
76  CHECK (stack.top().isRoot());
77  }
78 
79 
80  void
81  usePushedFrame ()
82  {
83  QueryFocusStack stack;
84  PMO& startPoint = retrieve_startElm();
85 
86  ScopePath& firstFrame = stack.top(); // remember for later
87  intrusive_ptr_add_ref (&firstFrame);
88  stack.top().navigate(startPoint);
89  stack.top().moveUp();
90  CHECK (Scope(startPoint).getParent() == stack.top().getLeaf());
91  CHECK (1 == stack.size());
92 
93  // now open a second path frame, pushing aside the initial one
94  ScopePath& secondFrame = stack.push(startPoint);
95  intrusive_ptr_add_ref (&secondFrame);
96  CHECK (2 == stack.size());
97  CHECK (secondFrame == stack.top());
98  CHECK (secondFrame.getLeaf() == startPoint);
99  CHECK (secondFrame.getLeaf() != firstFrame.getLeaf());
100 
101  // can still reach and manipulate the ref-count of the first frame
102  intrusive_ptr_add_ref (&firstFrame);
103  CHECK (2 == firstFrame.ref_count());
104  CHECK (1 == secondFrame.ref_count());
105 
106  // can use/navigate the stack top frame
107  stack.top().goRoot();
108  CHECK (!stack.top()); // now indeed at root == no path
109  CHECK (secondFrame.getLeaf().isRoot());
110  CHECK (secondFrame == stack.top());
111 
112  // now drop back to the first frame:
113  CHECK (1 == secondFrame.ref_count());
114  intrusive_ptr_release (&secondFrame);
115  CHECK (0 == secondFrame.ref_count());
116  stack.pop_unused();
117  CHECK (1 == stack.size());
118  CHECK (firstFrame == stack.top());
119 
120  // ...still pointing at the previous location
121  CHECK (Scope(startPoint).getParent() == stack.top().getLeaf());
122  CHECK (2 == firstFrame.ref_count());
123  }
124 
125 
126  void
127  automaticFrameHandling ()
128  {
129  QueryFocusStack stack;
130  PMO& startPoint = retrieve_startElm();
131 
132  ScopePath& firstFrame = stack.top(); // remember for later
133  stack.top().navigate(startPoint);
134  CHECK (1 == stack.size());
135  intrusive_ptr_add_ref (&firstFrame);
136 
137  // now open two new frames, but don't add ref-counts on them
138  ScopePath& secondFrame = stack.push(startPoint);
139  ScopePath& thirdFrame = stack.push(startPoint);
140  CHECK (3 == stack.size());
141  CHECK (1 == firstFrame.ref_count());
142  CHECK (0 == secondFrame.ref_count());
143  CHECK (0 == thirdFrame.ref_count());
144 
145  // any ref to top detects the non-referred-to state (by ref count==0)
146  // and will automatically pop and clean up...
147  ScopePath& newTop = stack.top();
148  CHECK (1 == stack.size());
149  CHECK (firstFrame == stack.top());
150  CHECK (isSameObject(newTop, firstFrame));
151  CHECK (stack.top().getLeaf() == startPoint);
152 
153  // second exercise: a pop_unused may even completely empty the stack
154  ScopePath& anotherFrame = stack.push(startPoint);
155  CHECK (0 == anotherFrame.ref_count());
156  CHECK (1 == firstFrame.ref_count());
157  intrusive_ptr_release (&firstFrame);
158  CHECK (0 == firstFrame.ref_count());
159  CHECK (firstFrame.getLeaf() == startPoint);
160 
161  stack.pop_unused();
162  CHECK (1 == stack.size());
163  // Note: don't use previously taken pointers
164  // or references anymore, after the stack
165  // triggered a cleanup!
166  ScopePath& anotherFrame2 = stack.top();
167  CHECK (0 == anotherFrame2.ref_count());
168  CHECK (anotherFrame2.getLeaf().isRoot());
169  anotherFrame2.navigate(startPoint);
170  CHECK (anotherFrame2.getLeaf() == startPoint);
171 
172  stack.top();
173  CHECK (1 == stack.size());
174  CHECK (stack.top().getLeaf().isRoot());
175  }
176 
177 
178  void
179  verify_errorHandling ()
180  {
181  QueryFocusStack stack;
182  PMO& startPoint = retrieve_startElm();
183 
184  ScopePath& firstFrame = stack.top(); // remember for later
185  stack.top().navigate(startPoint);
186  CHECK (1 == stack.size());
187  intrusive_ptr_add_ref (&firstFrame);
188 
189  ScopePath beforeInvalidNavigation = firstFrame;
190  Scope const& unrelatedScope = fabricate_invalidScope();
191 
192  // try to navigate to an invalid place
193  VERIFY_ERROR (INVALID_SCOPE, stack.top().navigate (unrelatedScope) );
194  CHECK (1 == stack.size());
195  CHECK (1 == firstFrame.ref_count());
196  CHECK (stack.top().getLeaf() == startPoint);
197 
198  // try to push an invalid place
199  VERIFY_ERROR (INVALID_SCOPE, stack.push (unrelatedScope) );
200  CHECK (1 == stack.size());
201  CHECK (1 == firstFrame.ref_count());
202  CHECK (stack.top().getLeaf() == startPoint);
203  }
204 
205 
206  void
207  clear ()
208  {
209  QueryFocusStack stack;
210  intrusive_ptr_add_ref (&stack.top());
211  stack.top().moveUp();
212  CHECK (stack.top().empty());
213 
214  PMO& startPoint = retrieve_startElm();
215  intrusive_ptr_add_ref ( & stack.push(startPoint) );
216  intrusive_ptr_add_ref ( & stack.push(startPoint) );
217  intrusive_ptr_add_ref ( & stack.push(startPoint) );
218  intrusive_ptr_add_ref ( & stack.push(startPoint) );
219  intrusive_ptr_add_ref ( & stack.push(startPoint) );
220  intrusive_ptr_add_ref ( & stack.push(startPoint) );
221  intrusive_ptr_add_ref ( & stack.push(startPoint) );
222  intrusive_ptr_add_ref ( & stack.push(startPoint) );
223  intrusive_ptr_add_ref ( & stack.push(startPoint) );
224  CHECK (10 == stack.size());
225  stack.pop_unused();
226  CHECK (10 == stack.size());
227  CHECK (1 == stack.top().ref_count());
228 
229  stack.clear();
230  CHECK (1 == stack.size());
231  CHECK (!stack.top().empty());
232  CHECK (stack.top().getLeaf().isRoot());
233  CHECK (0 == stack.top().ref_count());
234  }
235 
236  };
237 
238 
240  LAUNCHER (QueryFocusStack_test, "unit session");
241 
242 
243 }}}}// namespace steam::mobject::session::test
Unit test helper to generate deliberately wrong placement scopes.
ScopePath & push(Scope const &)
Open a new path frame, pushing down the current frame.
Definition: run.hpp:40
bool empty() const
an empty path doesn&#39;t even contain a root element.
Definition: scope-path.hpp:256
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
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.
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 pop_unused()
investigate the stack top and discard any path frames which aren&#39;t referred anymore (as indicated by ...
Implementation facility to work with and navigate nested scopes.
A custom stack holding ScopePath »frames«.
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