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