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)
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 "steam/asset/media.hpp"
31 #include "lib/depend-inject.hpp"
32 #include "lib/test/test-helper.hpp"
33 #include "lib/time/timevalue.hpp"
34 #include "lib/format-cout.hpp"
35 #include "lib/util.hpp"
36 
37 #include <string>
38 
39 using lib::test::showSizeof;
41 using lib::time::FSecs;
42 using lib::time::Time;
43 using util::isnil;
44 using std::string;
45 
46 
47 namespace steam {
48 namespace mobject {
49 namespace test {
50 
51  namespace { // shortcut for checking use-counts
52 
53  bool
54  checkUseCount (size_t cnt, uint additional=0)
55  {
56  static uint base_count=0;
57  if (!additional) // called for init
58  base_count = cnt;
59 
60  return cnt == base_count + additional;
61  }
62 
63  template<class REF>
64  bool
65  checkUseCount (REF const& ref, uint additional)
66  {
67  return checkUseCount(ref.use_count(), additional);
68  }
69  }
70 
71 
72  using LERR_(INVALID_PLACEMENTREF);
73  using LERR_(BOTTOM_MOBJECTREF);
74 
75  using session::Clip;
76  using session::PMedia;
77 
79  using session::PPIdx;
80 
81  using MediaAccessMock = lib::DependInject<vault::MediaAccessFacade>
82  ::Local<vault::test::MediaAccessMock>;
83 
84 
85 
86  /***********************************************************************/
96  class MObjectRef_test : public Test
97  {
98 
99  typedef Placement<MObject> PMObj;
100  typedef Placement<Clip> PClip;
102 
103 
104  virtual void
105  run (Arg)
106  {
107  MediaAccessMock useMockMedia;
108 
109 
110  // create data simulating a "Session"
111  PMObj testClip1 = asset::Media::create("test-1", asset::VIDEO)->createClip();
112  PMObj testClip2 = asset::Media::create("test-2", asset::VIDEO)->createClip();
113 
114  // set up a tie to fixed start positions (i.e. "properties of placement")
115  testClip1.chain (Time(FSecs(10)));
116  testClip2.chain (Time(FSecs(20)));
117 
118  CHECK (testClip1->isValid());
119  CHECK (testClip2->isValid());
120  CHECK (2 == testClip1.use_count()); // one by the placement and one by the clip-Asset
121  CHECK (2 == testClip2.use_count());
122 
123 
124  // Prepare an (test)Index
125  PPIdx index = SessionServiceMockIndex::install();
126  PMO& root = index->getRoot();
127 
128  // Add the Clips to "session" (here: dummy index)
129  PMObj::ID clip1ID = index->insert (testClip1, root);
130  PMObj::ID clip2ID = index->insert (testClip2, root);
131  CHECK (2 == index->size());
132 
133  // use the IDs returned on insertion to fetch
134  // language references to the placement instance within the index
135  // we'll use these language refs as base to create MObejctRef handles.
136  PMObj& pClip1 = index->find(clip1ID);
137  PMObj& pClip2 = index->find(clip2ID);
138 
139  CHECK (3 == pClip1.use_count()); // clip-Asset, original placement, new placement in index
140  CHECK (3 == pClip2.use_count());
141  checkUseCount(pClip1.use_count()); // set ref point for later checks
142 
143  // extract various kinds of IDs and refs
144  PMObj & rP1 (pClip1);
145  PMObj const& rP2 (pClip2);
146  PMObj::ID id1 = pClip1.getID();
147  PMObj::Id<Clip> id2 = pClip2.recastID<Clip>(); // explicit unchecked re-declaration of target type
148  LumieraUid luid = id1.get();
150  PlacementRef<Clip> ref1 (id1);
151  PlacementRef<MObject> ref2 (pClip2);
152 
153 
154  // -----Tests------------------
155  checkBuildMObjectRef (rP1, &pClip1);
156  checkBuildMObjectRef (rP2, &pClip2);
157  checkBuildMObjectRef (id1, &pClip1);
158  checkBuildMObjectRef (id2, &pClip2);
159  checkBuildMObjectRef (luid, &pClip1);
161  checkBuildMObjectRef (ref1, &pClip1);
162  checkBuildMObjectRef (ref2, &pClip2);
163 
164  checkComparison(rP1,rP2);
165  checkLifecycle (rP1,rP2);
166  checkTypeHandling (luid);
167  // -----Tests------------------
168 
169  // verify clean state
170  index->remove (pClip1);
171  index->remove (pClip2); // note: this invalidates pClip1 and pClip2;
172  CHECK (!ref1);
173  CHECK (!ref2);
174  CHECK (0 == index->size());
175  CHECK (1 == index.use_count());
176  CHECK (2 == testClip1.use_count());
177  CHECK (2 == testClip2.use_count());
178  index.reset();
179  }
180 
181 
182 
183  template<typename REF>
184  void
185  checkBuildMObjectRef (REF& refObj, void* placementAdr)
186  {
187  MORef<Clip> rMO;
188  CHECK (!rMO); // still empty (not bound)
189  CHECK (0==rMO.use_count());
190  cout << rMO << endl;
191  cout << showSizeof(rMO) << endl;
192 
193  // activate by binding to provided ref
194  rMO.activate(refObj);
195  CHECK (rMO); // now bound
196  cout << rMO << endl;
197 
198  // access MObject (Clip API)
199 // cout << rMO->operator string() << endl; /////////////////////TICKET #428
200  PMedia media = rMO->getMedia();
201  cout << media << endl;
202  Duration mediaLength = media->getLength();
203  CHECK (!isnil (mediaLength));
204  CHECK (rMO->isValid());
205 
206  // access the Placement-API
207  CHECK (checkUseCount(rMO, 1)); // now rMO shares ownership with the Placement --> use-count += 1
208  CHECK (Time::ZERO < rMO.getStartTime()); // (internally, this resolves to an ExplicitPlacement) /////////TICKET #332
209  CHECK ( rMO.isCompatible<MObject>());
210  CHECK ( rMO.isCompatible<Clip>());
211  CHECK (!rMO.isCompatible<TestSubMO1>());
212  Time start = rMO.getStartTime();
213 
214  // re-link to the Placement (note we get the Clip API!)
215  Placement<Clip> & refP = rMO.getPlacement();
216  CHECK (refP.isValid());
217  CHECK (refP.use_count() == rMO.use_count());
218  CHECK (checkUseCount(refP, 1)); // use count not changed
219  CHECK (&refP == placementAdr); // actually denotes the address of the original Placement in the "session"
220  cout << refP << endl;
221 
222  ExplicitPlacement exPla = refP.resolve();
223  CHECK (exPla.time == start); // recovered Placement resolves to the same time as provided by the proxied API
224  CHECK (checkUseCount(refP, 2)); // but now we've indeed created an additional owner (exPla)
225  CHECK (checkUseCount(rMO, 2));
226  }
227 
228 
229  void
230  checkComparison (PMO const& p1, PMO const& p2)
231  {
232  PlacementRef<Clip> pRef1 (p1);
233  PlacementRef<MObject> pRef2 (p2);
234 
235  MORef<MObject> rM;
236  MORef<Clip> rC;
237 
238  rM.activate (p1);
239  rC.activate (p2);
240  CHECK (rM && rC);
241  CHECK (!(rM == rC) && !(rC == rM));
242  CHECK ( (rM != rC) && (rC != rM));
243 
244  // mixed comparisons
245  CHECK ( (rM == pRef1) && (pRef1 == rM));
246  CHECK ( (rC == pRef2) && (pRef2 == rC));
247  CHECK (!(rM != pRef1) && !(pRef1 != rM));
248  CHECK (!(rC != pRef2) && !(pRef2 != rC));
249  CHECK ( (rM != pRef2) && (pRef2 != rM));
250  CHECK ( (rC != pRef1) && (pRef1 != rC));
251  CHECK (!(rM == pRef2) && !(pRef2 == rM));
252  CHECK (!(rC == pRef1) && !(pRef1 == rC));
253 
254  CHECK ( (rM == p1.getID()) );
255  CHECK ( (rC == p2.getID()) );
256  CHECK (!(rM != p1.getID()) );
257  CHECK (!(rC != p2.getID()) );
258  CHECK ( (rM != p2.getID()) );
259  CHECK ( (rC != p1.getID()) );
260  CHECK (!(rM == p2.getID()) );
261  CHECK (!(rC == p1.getID()) );
262 
263 
264  rC.activate (pRef1);
265  CHECK ( (rM == rC) && (rC == rM));
266  CHECK (!(rM != rC) && !(rC != rM));
267 
268  CHECK ( (rC == pRef1) && (pRef1 == rC));
269  CHECK (!(rC != pRef1) && !(pRef1 != rC));
270  CHECK ( (rC != pRef2) && (pRef2 != rC));
271  CHECK (!(rC == pRef2) && !(pRef2 == rC));
272 
273  CHECK ( (rC == p1.getID()) );
274  CHECK (!(rC != p1.getID()) );
275  CHECK ( (rC != p2.getID()) );
276  CHECK (!(rC == p2.getID()) );
277 
278 
279  rM.close();
280  CHECK (!rM);
281  CHECK (!(rM == rC) && !(rC == rM));
282  CHECK ( (rM != rC) && (rC != rM));
283 
284  CHECK (!(rM == pRef1) && !(pRef1 == rM));
285  CHECK ( (rM != pRef1) && (pRef1 != rM));
286  CHECK ( (rM != pRef2) && (pRef2 != rM));
287  CHECK (!(rM == pRef2) && !(pRef2 == rM));
288 
289  CHECK (!(rM == p1.getID()) );
290  CHECK ( (rM != p1.getID()) );
291  CHECK ( (rM != p2.getID()) );
292  CHECK (!(rM == p2.getID()) );
293  }
294 
295 
296  void
297  checkLifecycle (PMObj const& p1, PMObj const& p2)
298  {
299  CHECK (checkUseCount(p1, 0));
300  CHECK (checkUseCount(p2, 0));
301 
302  MORef<Clip> rMO;
303  CHECK (!rMO);
304  CHECK (0 == rMO.use_count());
305 
306  rMO.activate(p1);
307  CHECK (rMO);
308  CHECK (rMO->getMedia()->getFilename() == "test-1");
309  CHECK (checkUseCount(rMO, 1));
310  CHECK (checkUseCount(p1, 1)); // sharing ownership
311  CHECK (checkUseCount(p2, 0));
312 
313  rMO.activate(p2);
314  CHECK (rMO);
315  CHECK (rMO->getMedia()->getFilename() == "test-2");
316  CHECK (checkUseCount(rMO, 1));
317  CHECK (checkUseCount(p1, 0)); // detached, use count dropped to previous value
318  CHECK (checkUseCount(p2, 1)); // sharing ownership
319 
320  rMO.activate(p2);
321  CHECK (checkUseCount(rMO, 1)); // no change
322 
323  rMO.close();
324  CHECK (!rMO);
325  CHECK (checkUseCount(p1, 0));
326  CHECK (checkUseCount(p2, 0));
327 
328  VERIFY_ERROR (BOTTOM_MOBJECTREF, rMO.getPlacement() );
329  VERIFY_ERROR (BOTTOM_MOBJECTREF, rMO->getMedia() );
330  }
331 
332  void
333  checkTypeHandling (LumieraUid luid)
334  {
335  MObjectRef rMObj;
336  MORef<Clip> rClip;
337  MORef<TestSubMO1> rSub1;
338 
339  CHECK ( ! rMObj.use_count());
340  CHECK ( ! rClip.use_count());
341  CHECK ( ! rSub1.use_count());
342 
343  rMObj.activate(luid);
344  CHECK (checkUseCount(rMObj, 1));
345  CHECK ( ! rClip.use_count());
346  CHECK ( ! rSub1.use_count());
347 
348  rClip.activate(rMObj); // attach on existing MObjectRef
349  CHECK (checkUseCount(rMObj, 2));
350  CHECK (checkUseCount(rClip, 2));
351  CHECK ( ! rSub1.use_count());
352 
353  // impossible, because Clip isn't a subclass of TestSubMO1:
354  VERIFY_ERROR (INVALID_PLACEMENTREF, rSub1.activate(luid) );
355  VERIFY_ERROR (INVALID_PLACEMENTREF, rSub1 = rMObj );
356 
357  CHECK (rMObj->isValid());
358  CHECK (rClip->isValid());
359  CHECK (rMObj.getPlacement().getID() == rClip.getPlacement().getID());
360 
361  // doesn't compile, because the function isn't on MObject API:
362  // rMObj->getMedia();
363 
364  rClip.close();
365  CHECK (checkUseCount(rMObj, 1));
366  CHECK ( ! rClip.use_count());
367 
368  // can assign, because the actual type is checked:
369  rClip = rMObj;
370  CHECK (checkUseCount(rMObj, 2));
371  CHECK (checkUseCount(rClip, 2));
372 
373  cout << rClip << endl;
374  cout << rClip->getMedia()->ident << endl;
375  }
376  };
377 
378 
380  LAUNCHER (MObjectRef_test, "unit session");
381 
382 
383 }}} // 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:85
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:40
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:75
Steam-Layer implementation namespace root.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:299
MObject is the interface class for all "Media Objects".
Definition: mobject.hpp:70
This framework allows to (re)configure the lib::Depend front-end for dependency-injection.
External MObject/Placement reference.
Core of the session implementation datastructure.
Simplistic 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:220
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:140
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:468
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:71
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.