Lumiera  0.pre.03
»edit your freedom«
mobject-ref-test.cpp
Go to the documentation of this file.
1 /*
2  MObjectRef(Test) - validating basic properties of the external MObject reference tag
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 "steam/asset/media.hpp"
40 #include "lib/depend-inject.hpp"
41 #include "lib/test/test-helper.hpp"
42 #include "lib/time/timevalue.hpp"
43 #include "lib/format-cout.hpp"
44 #include "lib/util.hpp"
45 
46 #include <string>
47 
48 using lib::test::showSizeof;
50 using lib::time::FSecs;
51 using lib::time::Time;
52 using util::isnil;
53 using std::string;
54 
55 
56 namespace steam {
57 namespace mobject {
58 namespace test {
59 
60  namespace { // shortcut for checking use-counts
61 
62  bool
63  checkUseCount (size_t cnt, uint additional=0)
64  {
65  static uint base_count=0;
66  if (!additional) // called for init
67  base_count = cnt;
68 
69  return cnt == base_count + additional;
70  }
71 
72  template<class REF>
73  bool
74  checkUseCount (REF const& ref, uint additional)
75  {
76  return checkUseCount(ref.use_count(), additional);
77  }
78  }
79 
80 
81  using LERR_(INVALID_PLACEMENTREF);
82  using LERR_(BOTTOM_MOBJECTREF);
83 
84  using session::Clip;
85  using session::PMedia;
86 
88  using session::PPIdx;
89 
90  using MediaAccessMock = lib::DependInject<vault::MediaAccessFacade>
91  ::Local<vault::test::MediaAccessMock>;
92 
93 
94 
95  /***********************************************************************/
105  class MObjectRef_test : public Test
106  {
107 
108  typedef Placement<MObject> PMObj;
109  typedef Placement<Clip> PClip;
111 
112 
113  virtual void
114  run (Arg)
115  {
116  MediaAccessMock useMockMedia;
117 
118 
119  // create data simulating a "Session"
120  PMObj testClip1 = asset::Media::create("test-1", asset::VIDEO)->createClip();
121  PMObj testClip2 = asset::Media::create("test-2", asset::VIDEO)->createClip();
122 
123  // set up a tie to fixed start positions (i.e. "properties of placement")
124  testClip1.chain (Time(FSecs(10)));
125  testClip2.chain (Time(FSecs(20)));
126 
127  CHECK (testClip1->isValid());
128  CHECK (testClip2->isValid());
129  CHECK (2 == testClip1.use_count()); // one by the placement and one by the clip-Asset
130  CHECK (2 == testClip2.use_count());
131 
132 
133  // Prepare an (test)Index
134  PPIdx index = SessionServiceMockIndex::install();
135  PMO& root = index->getRoot();
136 
137  // Add the Clips to "session" (here: dummy index)
138  PMObj::ID clip1ID = index->insert (testClip1, root);
139  PMObj::ID clip2ID = index->insert (testClip2, root);
140  CHECK (2 == index->size());
141 
142  // use the IDs returned on insertion to fetch
143  // language references to the placement instance within the index
144  // we'll use these language refs as base to create MObejctRef handles.
145  PMObj& pClip1 = index->find(clip1ID);
146  PMObj& pClip2 = index->find(clip2ID);
147 
148  CHECK (3 == pClip1.use_count()); // clip-Asset, original placement, new placement in index
149  CHECK (3 == pClip2.use_count());
150  checkUseCount(pClip1.use_count()); // set ref point for later checks
151 
152  // extract various kinds of IDs and refs
153  PMObj & rP1 (pClip1);
154  PMObj const& rP2 (pClip2);
155  PMObj::ID id1 = pClip1.getID();
156  PMObj::Id<Clip> id2 = pClip2.recastID<Clip>(); // explicit unchecked re-declaration of target type
157  LumieraUid luid = id1.get();
159  PlacementRef<Clip> ref1 (id1);
160  PlacementRef<MObject> ref2 (pClip2);
161 
162 
163  // -----Tests------------------
164  checkBuildMObjectRef (rP1, &pClip1);
165  checkBuildMObjectRef (rP2, &pClip2);
166  checkBuildMObjectRef (id1, &pClip1);
167  checkBuildMObjectRef (id2, &pClip2);
168  checkBuildMObjectRef (luid, &pClip1);
170  checkBuildMObjectRef (ref1, &pClip1);
171  checkBuildMObjectRef (ref2, &pClip2);
172 
173  checkComparison(rP1,rP2);
174  checkLifecycle (rP1,rP2);
175  checkTypeHandling (luid);
176  // -----Tests------------------
177 
178  // verify clean state
179  index->remove (pClip1);
180  index->remove (pClip2); // note: this invalidates pClip1 and pClip2;
181  CHECK (!ref1);
182  CHECK (!ref2);
183  CHECK (0 == index->size());
184  CHECK (1 == index.use_count());
185  CHECK (2 == testClip1.use_count());
186  CHECK (2 == testClip2.use_count());
187  index.reset();
188  }
189 
190 
191 
192  template<typename REF>
193  void
194  checkBuildMObjectRef (REF& refObj, void* placementAdr)
195  {
196  MORef<Clip> rMO;
197  CHECK (!rMO); // still empty (not bound)
198  CHECK (0==rMO.use_count());
199  cout << rMO << endl;
200  cout << showSizeof(rMO) << endl;
201 
202  // activate by binding to provided ref
203  rMO.activate(refObj);
204  CHECK (rMO); // now bound
205  cout << rMO << endl;
206 
207  // access MObject (Clip API)
208 // cout << rMO->operator string() << endl; /////////////////////TICKET #428
209  PMedia media = rMO->getMedia();
210  cout << media << endl;
211  Duration mediaLength = media->getLength();
212  CHECK (!isnil (mediaLength));
213  CHECK (rMO->isValid());
214 
215  // access the Placement-API
216  CHECK (checkUseCount(rMO, 1)); // now rMO shares ownership with the Placement --> use-count += 1
217  CHECK (Time::ZERO < rMO.getStartTime()); // (internally, this resolves to an ExplicitPlacement) /////////TICKET #332
218  CHECK ( rMO.isCompatible<MObject>());
219  CHECK ( rMO.isCompatible<Clip>());
220  CHECK (!rMO.isCompatible<TestSubMO1>());
221  Time start = rMO.getStartTime();
222 
223  // re-link to the Placement (note we get the Clip API!)
224  Placement<Clip> & refP = rMO.getPlacement();
225  CHECK (refP.isValid());
226  CHECK (refP.use_count() == rMO.use_count());
227  CHECK (checkUseCount(refP, 1)); // use count not changed
228  CHECK (&refP == placementAdr); // actually denotes the address of the original Placement in the "session"
229  cout << refP << endl;
230 
231  ExplicitPlacement exPla = refP.resolve();
232  CHECK (exPla.time == start); // recovered Placement resolves to the same time as provided by the proxied API
233  CHECK (checkUseCount(refP, 2)); // but now we've indeed created an additional owner (exPla)
234  CHECK (checkUseCount(rMO, 2));
235  }
236 
237 
238  void
239  checkComparison (PMO const& p1, PMO const& p2)
240  {
241  PlacementRef<Clip> pRef1 (p1);
242  PlacementRef<MObject> pRef2 (p2);
243 
244  MORef<MObject> rM;
245  MORef<Clip> rC;
246 
247  rM.activate (p1);
248  rC.activate (p2);
249  CHECK (rM && rC);
250  CHECK (!(rM == rC) && !(rC == rM));
251  CHECK ( (rM != rC) && (rC != rM));
252 
253  // mixed comparisons
254  CHECK ( (rM == pRef1) && (pRef1 == rM));
255  CHECK ( (rC == pRef2) && (pRef2 == rC));
256  CHECK (!(rM != pRef1) && !(pRef1 != rM));
257  CHECK (!(rC != pRef2) && !(pRef2 != rC));
258  CHECK ( (rM != pRef2) && (pRef2 != rM));
259  CHECK ( (rC != pRef1) && (pRef1 != rC));
260  CHECK (!(rM == pRef2) && !(pRef2 == rM));
261  CHECK (!(rC == pRef1) && !(pRef1 == rC));
262 
263  CHECK ( (rM == p1.getID()) );
264  CHECK ( (rC == p2.getID()) );
265  CHECK (!(rM != p1.getID()) );
266  CHECK (!(rC != p2.getID()) );
267  CHECK ( (rM != p2.getID()) );
268  CHECK ( (rC != p1.getID()) );
269  CHECK (!(rM == p2.getID()) );
270  CHECK (!(rC == p1.getID()) );
271 
272 
273  rC.activate (pRef1);
274  CHECK ( (rM == rC) && (rC == rM));
275  CHECK (!(rM != rC) && !(rC != rM));
276 
277  CHECK ( (rC == pRef1) && (pRef1 == rC));
278  CHECK (!(rC != pRef1) && !(pRef1 != rC));
279  CHECK ( (rC != pRef2) && (pRef2 != rC));
280  CHECK (!(rC == pRef2) && !(pRef2 == rC));
281 
282  CHECK ( (rC == p1.getID()) );
283  CHECK (!(rC != p1.getID()) );
284  CHECK ( (rC != p2.getID()) );
285  CHECK (!(rC == p2.getID()) );
286 
287 
288  rM.close();
289  CHECK (!rM);
290  CHECK (!(rM == rC) && !(rC == rM));
291  CHECK ( (rM != rC) && (rC != rM));
292 
293  CHECK (!(rM == pRef1) && !(pRef1 == rM));
294  CHECK ( (rM != pRef1) && (pRef1 != rM));
295  CHECK ( (rM != pRef2) && (pRef2 != rM));
296  CHECK (!(rM == pRef2) && !(pRef2 == rM));
297 
298  CHECK (!(rM == p1.getID()) );
299  CHECK ( (rM != p1.getID()) );
300  CHECK ( (rM != p2.getID()) );
301  CHECK (!(rM == p2.getID()) );
302  }
303 
304 
305  void
306  checkLifecycle (PMObj const& p1, PMObj const& p2)
307  {
308  CHECK (checkUseCount(p1, 0));
309  CHECK (checkUseCount(p2, 0));
310 
311  MORef<Clip> rMO;
312  CHECK (!rMO);
313  CHECK (0 == rMO.use_count());
314 
315  rMO.activate(p1);
316  CHECK (rMO);
317  CHECK (rMO->getMedia()->getFilename() == "test-1");
318  CHECK (checkUseCount(rMO, 1));
319  CHECK (checkUseCount(p1, 1)); // sharing ownership
320  CHECK (checkUseCount(p2, 0));
321 
322  rMO.activate(p2);
323  CHECK (rMO);
324  CHECK (rMO->getMedia()->getFilename() == "test-2");
325  CHECK (checkUseCount(rMO, 1));
326  CHECK (checkUseCount(p1, 0)); // detached, use count dropped to previous value
327  CHECK (checkUseCount(p2, 1)); // sharing ownership
328 
329  rMO.activate(p2);
330  CHECK (checkUseCount(rMO, 1)); // no change
331 
332  rMO.close();
333  CHECK (!rMO);
334  CHECK (checkUseCount(p1, 0));
335  CHECK (checkUseCount(p2, 0));
336 
337  VERIFY_ERROR (BOTTOM_MOBJECTREF, rMO.getPlacement() );
338  VERIFY_ERROR (BOTTOM_MOBJECTREF, rMO->getMedia() );
339  }
340 
341  void
342  checkTypeHandling (LumieraUid luid)
343  {
344  MObjectRef rMObj;
345  MORef<Clip> rClip;
346  MORef<TestSubMO1> rSub1;
347 
348  CHECK ( ! rMObj.use_count());
349  CHECK ( ! rClip.use_count());
350  CHECK ( ! rSub1.use_count());
351 
352  rMObj.activate(luid);
353  CHECK (checkUseCount(rMObj, 1));
354  CHECK ( ! rClip.use_count());
355  CHECK ( ! rSub1.use_count());
356 
357  rClip.activate(rMObj); // attach on existing MObjectRef
358  CHECK (checkUseCount(rMObj, 2));
359  CHECK (checkUseCount(rClip, 2));
360  CHECK ( ! rSub1.use_count());
361 
362  // impossible, because Clip isn't a subclass of TestSubMO1:
363  VERIFY_ERROR (INVALID_PLACEMENTREF, rSub1.activate(luid) );
364  VERIFY_ERROR (INVALID_PLACEMENTREF, rSub1 = rMObj );
365 
366  CHECK (rMObj->isValid());
367  CHECK (rClip->isValid());
368  CHECK (rMObj.getPlacement().getID() == rClip.getPlacement().getID());
369 
370  // doesn't compile, because the function isn't on MObject API:
371  // rMObj->getMedia();
372 
373  rClip.close();
374  CHECK (checkUseCount(rMObj, 1));
375  CHECK ( ! rClip.use_count());
376 
377  // can assign, because the actual type is checked:
378  rClip = rMObj;
379  CHECK (checkUseCount(rMObj, 2));
380  CHECK (checkUseCount(rClip, 2));
381 
382  cout << rClip << endl;
383  cout << rClip->getMedia()->ident << endl;
384  }
385  };
386 
387 
389  LAUNCHER (MObjectRef_test, "unit session");
390 
391 
392 }}} // namespace steam::mobject::test
Reference tag denoting a placement attached to the session.
Automatically use custom string conversion in C++ stream output.
Subclass-1 is not defined "processible", thus will always be handled as DummyMO...
An active (smart-ptr like) external reference to a specifically placed MObject "instance" within the ...
Definition: mobject-ref.hpp:94
Media data represented a specific kind of Asset.
Core abstraction: completely resolved placement of an MObject Within the session model, all media objects are attached with the help of mobject::Placement elements.
Definition: run.hpp:49
Core abstraction: placement of a media object into session context.
Special kind of Placement, where the location of the MObject has been nailed down to a fixed position...
Per type specific configuration of instances created as service dependencies.
MObject in the Session to represent a clip on the timeline.
lib::time::Time getStartTime()
resolves the referred placement to an ExplicitPlacement and returns the found start time ...
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Unit test helper to access an emulated media file.
Core abstraction of the Session model: a media object.
A user visible/editable Clip is a reference to a contiguous sequence of media data loaded as Asset in...
static MediaFactory create
storage for the static MediaFactory instance
Definition: media.hpp:84
Steam-Layer implementation namespace root.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:308
MObject is the interface class for all "Media Objects".
Definition: mobject.hpp:79
This framework allows to (re)configure the lib::Depend front-end for dependency-injection.
External MObject/Placement reference.
Core of the session implementation datastructure.
Simple test class runner.
there is an implicit PlacementIndex available on a global level, by default implemented within the cu...
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
boost::rational< int64_t > FSecs
rational representation of fractional seconds
Definition: timevalue.hpp:229
A collection of frequently used helper functions to support unit testing.
void close()
deactivate this handle, so it isn&#39;t tied any longer to the associated implementation or service objec...
Definition: handle.hpp:149
A hierarchy of simple dummy-Media-Objects for easy unit testing.
Implementation level session API: PlacementIndex mock for tests.
A generic reference mechanism for Placements, as added to the current session.
Duration is the internal Lumiera time metric.
Definition: timevalue.hpp:477
MORef & activate(Placement< MO > const &placement)
activate an MObject reference, based on an existing placement, which needs to be contained (added to)...
Customised refcounting smart pointer template, built upon std::shared_ptr, but forwarding type relati...
Definition: trait.hpp:80
virtual bool isValid() const =0
MObject self-test (usable for asserting)
static PPIdx install()
Re-define the implicit PlacementIndex temporarily, e.g.
a family of time value like entities and their relationships.