/* SessionModifyParts(Test) - adding and removing elements, changing structure Copyright (C) Lumiera.org 2010, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************/ #include "lib/test/run.hpp" #include "proc/mobject/session.hpp" #include "proc/mobject/session/fixture.hpp" // TODO only temporarily needed //#include "proc/assetmanager.hpp" //////?? //#include "proc/asset/timeline.hpp" #include "proc/asset/sequence.hpp" //#include "lib/lumitime.hpp" #include "lib/util-foreach.hpp" #include "proc/mobject/session/testclip.hpp" #include "proc/mobject/mobject-ref.hpp" #include "proc/mobject/placement.hpp" #include "lib/query.hpp" #include #include #include #include using boost::ref; using std::tr1::placeholders::_1; using util::isSameObject; using util::and_all; using std::string; using std::cout; using std::set; namespace mobject { namespace session { namespace test { // using proc_interface::AssetManager; using proc_interface::PAsset; // using asset::PTimeline; using asset::PSequence; using asset::Sequence; // using lumiera::Time; using lumiera::Query; typedef MORef RClip; typedef PlacementMO::ID PID; /******************************************************************************* * @test perform the most important structural modifications on a session and * verify they're carried out properly. * - attaching tracks * - adding clips * * * @todo check more kinds of modifications, especially moving parts * @todo define criteria to be checked more precisely * @todo verify the actually dispatched commands */ class SessionModifyParts_test : public Test { virtual void run (Arg) { Session::current.reset(); CHECK (Session::current.isUp()); addTracks(); addObjects(); removeParts(); verify_dispatchedCommands(); } void addTracks() { PSess sess = Session::current; CHECK (sess->isValid()); PSequence seq = sess->defaults (Query ()); //////////////////////TICKET #549 CHECK (seq); #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #499 RTrack track1 = seq->attachTrack(); RTrack track2 = seq->attachTrack("track-2"); RTrack track21 = seq->attachTrack("track-2.1", track2); RTrack track22 = seq->attachTrack("track-2.2", "track-2"); QueryFocus& focus = sess->focus(); CHECK (track22 == focus.getObject()); RTrack track3 = seq->attachTrack("track-3", "root"); CHECK (track3 == focus.getObject()); RTrack track31 = sess->attach( asset::Struct::retrieve (Query ("id(track31)"))); CHECK (track31 == focus.getObject()); RTrack rootTrack = seq->rootTrack(); CHECK (3 == rootTrack->subTracks.size()); CHECK (track1 == rootTrack->subTracks[0]); CHECK (track2 == rootTrack->subTracks[1]); CHECK (track3 == rootTrack->subTracks[2]); CHECK (0 == track1->subTracks.size()); CHECK (2 == track2->subTracks.size()); CHECK (track21 == track2->subTracks[0]); CHECK (track22 == track2->subTracks[1]); CHECK (1 == track3->subTracks.size()); CHECK (track21 == track3->subTracks[0]); set allTracks; allTracks.insert(track1); allTracks.insert(track2); allTracks.insert(track21); allTracks.insert(track22); allTracks.insert(track3); allTracks.insert(track31); // verify we indeed covered all tracks known to the session.... CHECK (and_all (sess->all(), contains, ref(allTracks), _1 )); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #499 } void addObjects() { PSess sess = Session::current; CHECK (sess->isValid()); #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #499 QueryFocus& focus = sess->focus(); CHECK (focus.getObject().isCompatible()); RClip clip1 = sess->attach (TestClip::create()); RTrack track31 = clip.getParent(); CHECK (track31); CHECK ("track31" == track31->getNameID()); CHECK (1 == track31->clips.size()); CHECK (clip1 == track31->clips[0]); RClip clip2 = track31.attach (TestClip::create()); RClip clip3 = track31.attach (clip1); // creates a clone instance CHECK (clip1); CHECK (clip2); CHECK (clip3); CHECK (clip1 != clip2); CHECK (clip1 != clip3); CHECK (clip2 != clip3); CHECK (!isSharedPointee (clip1, clip2)); CHECK (!isSharedPointee (clip2, clip3)); CHECK ( isSharedPointee (clip1, clip3)); CHECK (isEquivalentPlacement (clip1, clip2)); CHECK (isEquivalentPlacement (clip2, clip3)); CHECK (isEquivalentPlacement (clip1, clip3)); RTrack track2 = sess->sequences[0] ->rootTrack() ->subTracks[1]; RClip clip4 = track2.attach (TestClip::create()); // now verify structure built up thus far CHECK (focus.getObject() == track2); // focus follows point-of-mutation CHECK (focus.contains (clip4)); CHECK (!focus.contains (clip1)); CHECK (!focus.contains (clip2)); CHECK (!focus.contains (clip3)); focus.attach (track31); CHECK (focus.getObject() == track31); CHECK (focus.contains (clip1)); CHECK (focus.contains (clip2)); CHECK (focus.contains (clip3)); CHECK (!focus.contains (clip4)); focus.reset(); CHECK (focus.getObject() == sess->getRoot()); CHECK (focus.contains (clip1)); // containment test includes sub-scopes CHECK (focus.contains (clip2)); CHECK (focus.contains (clip3)); CHECK (focus.contains (clip4)); CHECK (!focus.hasChild (clip1)); // but they are indeed nested more deeply CHECK (!focus.hasChild (clip2)); CHECK (!focus.hasChild (clip3)); CHECK (!focus.hasChild (clip4)); focus.attach (sess->sequences[0]->rootTrack()->subTracks[2]->subTracks[0]); // train wreck. Don't try it at home! CHECK (focus.getObject() == track31); // (this test is an exception, as we know the structure precisely // production code should always discover one level a time) CHECK ( focus.hasChild (clip1)); CHECK ( focus.hasChild (clip2)); CHECK ( focus.hasChild (clip3)); CHECK (!focus.hasChild (clip4)); // ...because this one is on track2, not track31 #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #499 } void removeParts() { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #499 PSess sess = Session::current; CHECK (sess->isValid()); RTrack track31 = sess->sequences[0]->rootTrack()->subTracks[2]->subTracks[0]; CHECK (track31); CHECK (3 == track31->clips.size()); RClip clip2 = track31->clips[1]; QueryFocus& focus = sess->focus(); focus.reset(); // navigate to root CHECK (focus.contains (clip2)); CHECK (clip2); clip2.purge(); CHECK (!clip2); CHECK (!focus.contains (clip2)); CHECK (2 == track31->clips.size()); CHECK (clip2 != track31->clips[1]); CHECK (focus.getObject() == track31); // focus follows point-of-mutation // Using the query-focus to explore the contents of this current object (track31) ScopeQuery::iterator discoverClips = focus.explore(); CHECK (discoverClips); RClip clip1 = *discoverClips; ++discoverClips; RClip clip3 = *discoverClips; ++discoverClips; CHECK (!discoverClips); CHECK (track31->clips[0] == clip1); CHECK (track31->clips[1] == clip3); /* please note: the clips aren't discovered in any defined order (hashtable!) * especially, the order doesn't match the order of addition! * thus, what's called clip1 here may or may not be * what we called clip1 in addObjects() */ RTrack track3 = track31.getParent(); focus.reset(); // back to root CHECK (focus.contains (clip1)); CHECK (focus.contains (clip3)); CHECK (focus.contains (track3)); CHECK (focus.contains (track31)); CHECK (clip1); CHECK (clip3); CHECK (track3); CHECK (track31); sess->purge (track31); CHECK (focus.getObject() == track3); focus.reset(); CHECK ( focus.contains (track3)); CHECK (!focus.contains (clip1)); CHECK (!focus.contains (clip3)); CHECK (!focus.contains (track31)); CHECK (!clip1); CHECK (!clip3); CHECK (!track31); CHECK (track3); track3.purge(); CHECK (!track3); PSequence aSequence = sess->sequences[0]; CHECK (focus.getObject() == aSequence->rootTrack()); CHECK (2 == aSequece->rootTrack()->subTracks.size()); CHECK ( contains (sess->sequences, aSequence)); aSequence->rootTrack().purge(); // automatically kills the sequence as well (sequence == facade to the root track) CHECK (!contains (sess->sequences, aSequence)); CHECK (0 == sess->sequences.size()); CHECK (0 == sess->timelines.size()); // killing the sequence also cascaded to the timeline and binding CHECK (!sess->isValid()); // thus effectively the session is now invalid (no timeline) CHECK (focus.getObject() == sess->getRoot()); PID currRoot = sess->getRoot.getPlacement().getID(); sess->getRoot().purge(); // purging the root scope effectively resets the session to defaults CHECK (currRoot == sess->getRoot.getPlacement.getID); // but the root element itself is retained CHECK (sess->isValid()); CHECK (1 == sess->timelines.size()); CHECK (1 == sess->sequences.size()); CHECK (aSequence != sess->sequences[0]); CHECK (aSequence.use_count() == 1); // we're holding the last remaining reference #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #499 } void verify_dispatchedCommands() { TODO ("verify the commands issued by this test"); ////////////////////////TICKET #567 } }; /** Register this test class... */ LAUNCHER (SessionModifyParts_test, "unit session"); }}} // namespace mobject::session::test