Lumiera  0.pre.03
»edit your freedom«
model-port-registry-test.cpp
Go to the documentation of this file.
1 /*
2  ModelPortRegistry(Test) - verify handling of model ports
3 
4  Copyright (C) Lumiera.org
5  2010, 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"
31 #include "steam/asset/timeline.hpp"
32 #include "steam/asset/pipe.hpp"
33 #include "common/query.hpp"
34 #include "lib/util.hpp"
35 
36 
37 namespace steam {
38 namespace fixture {
39 namespace test {
40 
41  using util::isSameObject;
42  using util::isnil;
43 
44  using asset::Pipe;
45  using asset::PPipe;
46  using asset::Struct;
47  using asset::Timeline;
48  using asset::PTimeline;
49  using mobject::ModelPort;
50  using lumiera::Query;
51 
52  using PID = asset::ID<Pipe>;
53  using TID = asset::ID<Struct>;
54 
55  using MPDescriptor = ModelPortRegistry::ModelPortDescriptor const&;
56 
57  using mobject::LUMIERA_ERROR_INVALID_MODEL_PORT;
58  using mobject::LUMIERA_ERROR_UNCONNECTED_MODEL_PORT;
59 
60 
61  namespace { // test environment
62 
63  inline PID
64  getPipe (string id)
65  {
66  return Pipe::query ("id("+id+")");
67  }
68 
69  inline TID
70  getTimeline (string id)
71  {
72  return asset::Struct::retrieve (Query<Timeline> ("id("+id+")"))->getID();
73  }
74 
75  struct TestContext
76  {
77  ModelPortRegistry registry_;
78  ModelPortRegistry* previous_;
79 
82  : registry_()
83  , previous_(ModelPortRegistry::setActiveInstance (registry_))
84  { }
85 
88  {
89  if (previous_)
91  else
93  }
94  };
95  }
96 
97 
98 
99 
100  /*****************************************************************************/
111  class ModelPortRegistry_test : public Test
112  {
113 
114  virtual void
115  run (Arg)
116  {
117  TestContext ctx;
118 
119  fabricating_ModelPorts (ctx.registry_);
120  accessing_ModelPorts();
121  transactionalSwitch (ctx.registry_);
122  }
123 
124 
125  void
126  fabricating_ModelPorts (ModelPortRegistry& registry)
127  {
128  /* == some Assets to play with == */
129  PID pipeA = getPipe ("pipeA");
130  PID pipeB = getPipe ("pipeB");
131  TID someTimeline = getTimeline ("some_test_Timeline");
132 
133  // start out with defining some new model ports......
134  MPDescriptor p1 = registry.definePort (pipeA, someTimeline);
135  MPDescriptor p2 = registry.definePort (pipeB, someTimeline);
136 
137  CHECK (registry.contains (pipeA));
138  CHECK (registry.contains (pipeB));
139 
140  VERIFY_ERROR (DUPLICATE_MODEL_PORT, registry.definePort(pipeB, someTimeline) );
141  CHECK (registry.contains (pipeB));
142 
143  CHECK (pipeA == p1.id());
144  CHECK (pipeB == p2.id());
145  CHECK (someTimeline == p1.holder());
146  CHECK (someTimeline == p2.holder());
147 
148  registry.commit();
149  }
150 
151 
152  void
153  accessing_ModelPorts ()
154  {
155  PID pipeA = getPipe ("pipeA");
156  PID pipeB = getPipe ("pipeB");
157  PID pipeWC = getPipe ("WCpipe");
158 
159  ModelPort mp1(pipeA);
160  ModelPort mp2(pipeB);
161 
162  VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort unbefitting(pipeWC) );
163 
164  ModelPort mp1x(pipeA); // can be created multiple times
165  ModelPort mp2x(mp1x); // can be copied at will
166  ModelPort mpNull; // can be default constructed (->unconnected)
167 
168  CHECK (mp1);
169  CHECK (mp2);
170  CHECK (mp1x);
171  CHECK (mp2x);
172  CHECK (!mpNull); // bool check verifies setup and connected state
173 
174  CHECK ( ModelPort::exists (pipeA)); // this is the same check, but invoked just with an pipe-ID
175  CHECK ( ModelPort::exists (pipeB));
176  CHECK (!ModelPort::exists (pipeWC));
177 
178  CHECK (mp1 == mp1x);
179  CHECK (!isSameObject (mp1, mp1x));
180  CHECK (mp1 != mp2);
181  CHECK (mp2 != mp1);
182  CHECK (mp1 != mpNull);
183  CHECK (mp2 != mpNull);
184 
185  CHECK (mp1.pipe() == pipeA);
186  CHECK (mp2.pipe() == pipeB);
187  CHECK (mp1x.pipe() == pipeA);
188  VERIFY_ERROR (UNCONNECTED_MODEL_PORT, mpNull.pipe()); // any further operations on an unconnected port will throw
189  VERIFY_ERROR (UNCONNECTED_MODEL_PORT, mpNull.holder());
190 
191  CHECK (mp1.streamType() == pipeA.streamType());
192  }
193 
194 
195  void
196  transactionalSwitch (ModelPortRegistry& registry)
197  {
198  PID pipeA = getPipe ("pipeA");
199  PID pipeB = getPipe ("pipeB");
200  PID pipeWC = getPipe ("WCpipe");
201 
202  CHECK ( ModelPort::exists (pipeB));
203  CHECK (!ModelPort::exists (pipeWC));
204 
205  CHECK (ModelPort::exists (pipeA));
206  CHECK (registry.contains (pipeA));
207  registry.remove (pipeA);
208  CHECK (!registry.contains (pipeA)); // removed from the current (pending) transaction
209  CHECK ( ModelPort::exists (pipeA)); // but not yet publicly visible
210 
211  // now create a new and differing definition of port A
212  TID anotherTimeline = getTimeline ("another_test_Timeline");
213  MPDescriptor p1 = registry.definePort (pipeA, anotherTimeline);
214  CHECK (registry.contains (pipeA));
215  CHECK (anotherTimeline == p1.holder());
216  CHECK (ModelPort(pipeA).holder() != anotherTimeline);
217 
218  registry.remove (pipeB); // some more wired definitions
219  registry.definePort (pipeWC, anotherTimeline);
220  CHECK (!registry.contains (pipeB));
221  CHECK ( registry.contains (pipeWC));
222  CHECK ( ModelPort::exists (pipeB));
223  CHECK (!ModelPort::exists (pipeWC));
224  CHECK ( registry.isRegistered (pipeB)); // this is the same as ModelPort::exists
225  CHECK (!registry.isRegistered (pipeWC)); //
226  // Note: pending transaction not yet committed
227  ModelPort portA(pipeA); // ...... thus the changes aren't reflected to client code
228  ModelPort portB(pipeB);
229  VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort ineptly(pipeWC));
230  CHECK (portA);
231  CHECK (portB);
232  CHECK (portA.pipe() == pipeA);
233  CHECK (portB.pipe() == pipeB);
234  CHECK (portA.holder() != anotherTimeline);
235 
236  registry.commit();
237  CHECK ( ModelPort::exists (pipeA)); // now all our changes got publicly visible
238  CHECK (!ModelPort::exists (pipeB));
239  CHECK ( ModelPort::exists (pipeWC));
240  CHECK ( portA);
241  CHECK (!portB);
242  CHECK (portA.holder() == anotherTimeline);
243  CHECK (portA.pipe() == pipeA);
244  VERIFY_ERROR (INVALID_MODEL_PORT, portB.pipe());
245 
246  ModelPort pwc(pipeWC); // now clients may also use the now officially promoted new port
247  CHECK (pwc);
248  CHECK (pwc.pipe() == pipeWC);
249  CHECK (pwc.holder() == anotherTimeline);
250 
251  // Next: doing several changes,
252  // but finally *not* committing them...
253  CHECK ( registry.contains (pipeA));
254  CHECK (!registry.contains (pipeB));
255  CHECK ( registry.contains (pipeWC));
256  registry.remove (pipeA);
257  registry.clear(); // remove everything from the pending transaction
258  CHECK (!registry.contains (pipeA));
259  CHECK (!registry.contains (pipeB));
260  CHECK (!registry.contains (pipeWC));
261 
262  registry.definePort (pipeB, anotherTimeline);
263  CHECK ( registry.contains (pipeB));
264  CHECK (!portB); // not committed and thus not visible
265  CHECK (portA);
266  CHECK (pwc);
267 
268  registry.rollback();
269  CHECK ( registry.contains (pipeA)); // no effect to the officially visible state
270  CHECK (!registry.contains (pipeB));
271  CHECK ( registry.contains (pipeWC));
272 
273  VERIFY_ERROR(INVALID_MODEL_PORT, registry.get(pipeB) );
274  CHECK (!portB);
275  }
276  };
277 
278 
280  LAUNCHER (ModelPortRegistry_test, "unit fixture session builder");
281 
282 
283 
284 }}} // namespace steam::fixture::test
ModelPortDescriptor const & get(PID) const
basic access operation: access the descriptor of a currently valid model port.
ModelPortDescriptor const & definePort(PID pipe, StID element_exposing_this_port)
create and register a new model port entry, within the pending transaction
A "processing pipe" represented as Asset.
void clear()
schedule removal of all registry contents.
bool contains(PID) const
does the transaction currently being built already contain a model port registration for the given ID...
Basic and generic representation of an internal query.
void commit()
activate pending model port changes.
static bool exists(ID< asset::Pipe >)
check if the global model port registration contains a mapping for the given pipe-ID ...
Definition: run.hpp:49
Mutation and management facility for model ports within the builder.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Steam-Layer implementation namespace root.
structural asset corresponding to the part of the model forming a processing pipe for generating medi...
Definition: pipe.hpp:79
static StructFactory retrieve
storage for the static StructFactory instance
Definition: struct.hpp:116
ID< asset::Pipe > pipe() const
access the Pipe (ID) of the global model port registered with the ID underlying this model port...
static ModelPortRegistry * setActiveInstance(ModelPortRegistry &newRegistry)
switch the implicit link to the global ModelPort registry to point to the given implementation instan...
static void shutdown()
globally deactivate access to model ports
Management facility for tracking model ports.
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.
StreamType::ID streamType() const
allows to fetch the StreamType directly just from a Pipe-ID
Definition: pipe.hpp:130
static PPipe query(string const &properties)
convenience shortcut for retrieving default configured pipes
Definition: pipe.cpp:66
Handle designating a point within the model, where actually output data can be pulled.
Definition: model-port.hpp:104
Customised refcounting smart pointer template, built upon std::shared_ptr, but forwarding type relati...
Definition: trait.hpp:80
ID< asset::Struct > holder() const
access the timeline (or similar structural element) holding a global pipe which corresponds to this m...
key abstraction: structural asset Created automatically as a sideeffect of building the structure of ...
Definition: struct.hpp:113
StreamType::ID streamType() const
convenience shortcut to access the stream type associated with the pipe-ID corresponding to this mode...
void rollback()
discard pending changes.
Generic interface to express a query for specifically typed result elements exposing some capabilitie...
Definition: query.hpp:279
void remove(PID)
remove a model port entry from the pending transaction
Top level structural element within the session.
bool isSameObject(A const &a, B const &b)
compare plain object identity, bypassing any custom comparison operators.
Definition: util.hpp:372