Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
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"
34#include "lib/format-cout.hpp"
35#include "lib/util.hpp"
36
37#include <string>
38
42using lib::time::Time;
43using util::isnil;
44using std::string;
45
46
47namespace steam {
48namespace mobject {
49namespace 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
82 ::Local<vault::test::MediaAccessMock>;
83
84
85
86 /***********************************************************************/
96 class MObjectRef_test : public Test
97 {
98
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
236 MORef<Clip> rC;
237
238 rM.activate (p1);
239 rC.activate (p2);
240 CHECK (rM and rC);
241 CHECK (!(rM == rC) and !(rC == rM));
242 CHECK ( (rM != rC) and (rC != rM));
243
244 // mixed comparisons
245 CHECK ( (rM == pRef1) and (pRef1 == rM));
246 CHECK ( (rC == pRef2) and (pRef2 == rC));
247 CHECK (!(rM != pRef1) and !(pRef1 != rM));
248 CHECK (!(rC != pRef2) and !(pRef2 != rC));
249 CHECK ( (rM != pRef2) and (pRef2 != rM));
250 CHECK ( (rC != pRef1) and (pRef1 != rC));
251 CHECK (!(rM == pRef2) and !(pRef2 == rM));
252 CHECK (!(rC == pRef1) and !(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) and (rC == rM));
266 CHECK (!(rM != rC) and !(rC != rM));
267
268 CHECK ( (rC == pRef1) and (pRef1 == rC));
269 CHECK (!(rC != pRef1) and !(pRef1 != rC));
270 CHECK ( (rC != pRef2) and (pRef2 != rC));
271 CHECK (!(rC == pRef2) and !(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) and !(rC == rM));
282 CHECK ( (rM != rC) and (rC != rM));
283
284 CHECK (!(rM == pRef1) and !(pRef1 == rM));
285 CHECK ( (rM != pRef1) and (pRef1 != rM));
286 CHECK ( (rM != pRef2) and (pRef2 != rM));
287 CHECK (!(rM == pRef2) and !(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
334 {
335 MObjectRef rMObj;
336 MORef<Clip> rClip;
337 MORef<TestSubMO1> rSub1;
338
339 CHECK (not rMObj.use_count());
340 CHECK (not rClip.use_count());
341 CHECK (not rSub1.use_count());
342
343 rMObj.activate(luid);
344 CHECK (checkUseCount(rMObj, 1));
345 CHECK (not rClip.use_count());
346 CHECK (not rSub1.use_count());
347
348 rClip.activate(rMObj); // attach on existing MObjectRef
349 CHECK (checkUseCount(rMObj, 2));
350 CHECK (checkUseCount(rClip, 2));
351 CHECK (not 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 (not 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
This framework allows to (re)configure the lib::Depend front-end for dependency-injection.
void close()
deactivate this handle, so it isn't tied any longer to the associated implementation or service objec...
Definition handle.hpp:140
Customised refcounting smart pointer template, built upon std::shared_ptr, but forwarding type relati...
Definition p.hpp:77
Duration is the internal Lumiera time metric.
Lumiera's internal time value datatype.
static const Time ZERO
static MediaFactory create
storage for the static MediaFactory instance
Definition media.hpp:75
Special kind of Placement, where the location of the MObject has been nailed down to a fixed position...
An active (smart-ptr like) external reference to a specifically placed MObject "instance" within the ...
MORef & activate(Placement< MO > const &placement)
activate an MObject reference, based on an existing placement, which needs to be contained (added to)...
lib::time::Time getStartTime()
resolves the referred placement to an ExplicitPlacement and returns the found start time
Placement< MO > & getPlacement() const
size_t use_count() const
bool isCompatible() const
MObject is the interface class for all "Media Objects".
Definition mobject.hpp:72
virtual bool isValid() const =0
MObject self-test (usable for asserting)
Reference tag denoting a placement attached to the session.
A refcounting Handle to an MObject of type MO, used to constrain or explicitly specify the location w...
A user visible/editable Clip is a reference to a contiguous sequence of media data loaded as Asset in...
there is an implicit PlacementIndex available on a global level, by default implemented within the cu...
static PPIdx install()
Re-define the implicit PlacementIndex temporarily, e.g.
void checkBuildMObjectRef(REF &refObj, void *placementAdr)
void checkLifecycle(PMObj const &p1, PMObj const &p2)
void checkComparison(PMO const &p1, PMO const &p2)
Per type specific configuration of instances created as service dependencies.
#define LERR_(_NAME_)
Definition error.hpp:45
Core abstraction: completely resolved placement of an MObject Within the session model,...
Automatically use custom string conversion in C++ stream output.
lumiera_uid * LumieraUid
Definition hash-value.h:41
unsigned int uint
Definition integral.hpp:29
Unit test helper to access an emulated media file.
Media data represented a specific kind of Asset.
External MObject/Placement reference.
MObject in the Session to represent a clip on the timeline.
Core abstraction of the Session model: a media object.
string showSizeof(size_t siz, string name)
for printing sizeof().
boost::rational< int64_t > FSecs
rational representation of fractional seconds
std::shared_ptr< PlacementIndex > PPIdx
lib::DependInject< vault::MediaAccessFacade > ::Local< vault::test::MediaAccessMock > MediaAccessMock
MORef< MObject > MObjectRef
Steam-Layer implementation namespace root.
Test runner and basic definitions for tests.
bool isnil(lib::time::Duration const &dur)
Core of the session implementation datastructure.
A generic reference mechanism for Placements, as added to the current session.
Core abstraction: placement of a media object into session context.
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Definition run.hpp:116
Implementation level session API: PlacementIndex mock for tests.
Subclass-1 is not defined "processible", thus will always be handled as DummyMO...
A hierarchy of simple dummy-Media-Objects for easy unit testing.
A collection of frequently used helper functions to support unit testing.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
a family of time value like entities and their relationships.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...