/* DiffTreeApplication(Test) - demonstrate the basics of tree diff representation Copyright (C) Lumiera.org 2015, 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 "lib/diff/tree-diff-application.hpp" #include "lib/iter-adapter-stl.hpp" #include "lib/time/timevalue.hpp" #include "lib/format-util.hpp" #include "lib/util.hpp" #include #include using lib::iter_stl::snapshot; using util::isnil; using util::join; using std::string; using std::vector; using lib::time::Time; namespace lib { namespace diff{ namespace test{ namespace {//Test fixture.... // define some GenNode elements // to act as templates within the concrete diff // NOTE: everything in this diff language is by-value const GenNode ATTRIB1("α", 1), // attribute α = 1 ATTRIB2("β", 2L), // attribute α = 2L (int64_t) ATTRIB3("γ", 3.45), // attribute γ = 3.45 (double) TYPE_X("type", "X"), // a "magic" type attribute "X" TYPE_Y("type", "Y"), // CHILD_A("a"), // unnamed string child node CHILD_B('b'), // unnamed char child node CHILD_T(Time(12,34,56,78)), // unnamed time value child SUB_NODE = MakeRec().genNode(), // empty anonymous node used to open a sub scope ATTRIB_NODE = MakeRec().genNode("δ"), // empty named node to be attached as attribute δ CHILD_NODE = SUB_NODE; // yet another child node, same ID as SUB_NODE (!) }//(End)Test fixture /***********************************************************************//** * @test Demonstration/Concept: a description language for list differences. * The representation is given as a linearised sequence of verb tokens. * This test demonstrates the application of such a diff representation * to a given source list, transforming this list to hold the intended * target list contents. * * @see session-structure-mapping-test.cpp */ class DiffTreeApplication_test : public Test , TreeDiffLanguage { using DiffSeq = iter_stl::IterSnapshot; DiffSeq populationDiff() { return snapshot({ins(TYPE_X) , ins(ATTRIB1) , ins(ATTRIB2) , ins(ATTRIB3) , ins(CHILD_A) , ins(CHILD_T) , ins(CHILD_T) , ins(SUB_NODE) , mut(SUB_NODE) , ins(CHILD_B) , ins(CHILD_A) , emu(SUB_NODE) }); } DiffSeq mutationDiff() { return snapshot({after(Ref::ATTRIBS) // fast forward to the first child , find(CHILD_T) , pick(CHILD_A) , skip(CHILD_T) , del(CHILD_T) , pick(Ref::CHILD) // pick a child anonymously , mut(Ref::THIS) , ins(ATTRIB3) , ins(ATTRIB_NODE) , find(CHILD_A) , del(CHILD_B) , ins(CHILD_NODE) , ins(CHILD_T) , skip(CHILD_A) , mut(CHILD_NODE) , ins(TYPE_Y) , ins(ATTRIB2) , emu(CHILD_NODE) , mut(ATTRIB_NODE) , ins(CHILD_A) , ins(CHILD_A) , ins(CHILD_A) , emu(ATTRIB_NODE) , emu(Ref::THIS) }); } virtual void run (Arg) { Rec::Mutator target; Rec& subject = target; DiffApplicator application(target); application.consume(populationDiff()); CHECK (!isnil (subject)); // nonempty -- content has been added CHECK ("X" == subject.getType()); // type was set to "X" CHECK (1 == subject.get("α").data.get()); // has gotten our int attribute "α" CHECK (2L == subject.get("β").data.get()); // ... the long attribute "β" CHECK (3.45 == subject.get("γ").data.get()); // ... and double attribute "γ" auto scope = subject.scope(); // look into the scope contents... CHECK ( *scope == CHILD_A); // there is CHILD_A CHECK (*++scope == CHILD_T); // followed by a copy of CHILD_T CHECK (*++scope == CHILD_T); // and another copy of CHILD_T CHECK (*++scope == MakeRec().appendChild(CHILD_B) // and there is a nested Record .appendChild(CHILD_A) // with CHILD_B .genNode(SUB_NODE.idi.getSym())); // and CHILD_A CHECK (isnil(++scope)); // thats all -- no more children application.consume(mutationDiff()); CHECK (join (subject.keys()) == "α, β, γ"); // the attributes weren't altered scope = subject.scope(); // but the scope was reordered CHECK ( *scope == CHILD_T); // CHILD_T CHECK (*++scope == CHILD_A); // CHILD_A Rec nested = (++scope)->data.get(); // and our nested Record, which too has been altered: CHECK (nested.get("γ").data.get() == 3.45); // it carries now an attribute "δ", which is again CHECK (nested.get("δ").data.get() == MakeRec().appendChild(CHILD_A) // a nested Record with three children CHILD_A .appendChild(CHILD_A) // .appendChild(CHILD_A) // .genNode("δ")); // auto subScope = nested.scope(); // and within the nested sub-scope we find CHECK ( *subScope == CHILD_A); // CHILD_A CHECK (*++subScope == MakeRec().type("Y") // a yet-again nested sub-Record of type "Y" .set("β", 2L ) // with just an attribute "β" == 2L .genNode(CHILD_NODE.idi.getSym())); // (and an empty child scope) CHECK (*++subScope == CHILD_T); // followed by another copy of CHILD_T CHECK (isnil (++subScope)); // CHECK (isnil (++scope)); // and nothing beyond that. } }; /** Register this test class... */ LAUNCHER (DiffTreeApplication_test, "unit common"); }}} // namespace lib::diff::test