/* GenNode(Test) - fundamental properties of a generic tree node element 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. * *****************************************************/ /** @file gen-node-test.cpp ** unit test \ref GenNode_test */ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "lib/format-cout.hpp" #include "lib/diff/gen-node.hpp" #include "lib/diff/record.hpp" #include "lib/time/timevalue.hpp" #include "lib/util-quant.hpp" #include "lib/util.hpp" #include using util::isnil; using util::contains; using util::isSameObject; using util::almostEqual; using lib::hash::LuidH; using lib::time::FSecs; using lib::time::Time; using lib::time::TimeSpan; using lib::test::randTime; using std::string; namespace lib { namespace diff{ namespace test{ using error::LERR_(WRONG_TYPE); using error::LERR_(BOTTOM_VALUE); namespace {//Test fixture.... const double PI = 3.14159265358979323846264338328; }//(End)Test fixture /*****************************************************************************//** * @test Verify properties of a special collection type shaped for * external representation of object-like data. * - GenNode elements can be created "right away", picking up * the given type, assumed that the payload is one of the * supported basic types. * - optionally, GenNode elements can be named * - unnamed elements get a marker ID plus unique number extension * - object-like elements can be represented by using a diff:Record * as payload. Obviously, the resulting data structure type is recursive. * - a shortcut is provided to simplify defining empty baseline objects * - a special notation is provided to create "id references", which * can be used to stand-in for an "object" (Record). This shortcut * notation is relevant for the tree diff language -- used within * Lumiera as "External Tree Description" of object networks. * * @see IndexTable * @see DiffListApplication_test */ class GenNode_test : public Test { virtual void run (Arg) { simpleUsage(); equalityMatch(); objectShortcut(); symbolReference(); sequenceIteration(); convenienceRecAccess(); } void simpleUsage() { // can build from the supported value types GenNode n1(42); CHECK (42 == n1.data.get()); CHECK (!n1.isNamed()); CHECK (contains (n1.idi.getSym(), "_CHILD_")); CHECK (contains (name(n1), "_CHILD_")); // can optionally be named GenNode n2("π", PI); CHECK (almostEqual (PI, n2.data.get())); CHECK (n2.isNamed()); CHECK ("π" == n2.idi.getSym()); CHECK ("π" == name(n2)); // is a copyable value GenNode n11(n1); CHECK (n1 == n11); CHECK (42 == n11.data.get()); // is assignable with compatible payload value n11.data = 24; CHECK (n1 != n11); CHECK (24 == n11.data.get()); CHECK (42 == n1.data.get()); // is assignable within the same kind of value n1 = n11; CHECK (n1 == n11); // but assignment may not alter payload type VERIFY_ERROR (WRONG_TYPE, n1 = n2 ); // can build recursive data structures GenNode n3(Rec({GenNode("type", "spam"), GenNode("ham", "eggs")})); CHECK ("spam" == n3.data.get().getType()); CHECK ("eggs" == n3.data.get().get("ham").data.get()); CHECK ("ham" == n3.data.get().get("ham").idi.getSym()); CHECK (n3.data.get().get("ham").isNamed()); CHECK (!n3.isNamed()); cout << n3 <())); CHECK ("NIL" == o0.data.get().getType()); CHECK (o1.isNamed()); CHECK ("νόμος" == o1.idi.getSym()); CHECK (isnil(o1.data.get())); CHECK (!o2.isNamed()); CHECK ("spam" == o2.data.get().getType()); CHECK (isnil(o2.data.get())); CHECK (o3.isNamed()); CHECK ("μάθησις" == o3.idi.getSym()); CHECK ("NIL" == o3.data.get().getType()); CHECK (GenNode("Ψ", int64_t(42)) == o3.data.get().get("Ψ")); CHECK (42L == o3.data.get().get("Ψ").data.get()); CHECK (almostEqual (PI, o3.data.get().get("π").data.get())); LuidH luid; //Demonstration: object builder is based on the mutator mechanism for Records... auto o4 = Rec::Mutator(o2.data.get()) // ...use GenNode o2 as starting point .appendChild(GenNode("τ", Time(1,2,3,4))) // a named node with Time value .scope('*' // a char node ,"★" // a string node ,luid // a hash value (LUID) ,TimeSpan(Time::ZERO, FSecs(23,25)) // a time span ,MakeRec().type("ham").scope("eggs").genNode()) // a spam object .genNode("baked beans"); // ---> finish into named node CHECK (o4.isNamed()); CHECK ("baked beans" == o4.idi.getSym()); CHECK ("spam" == o4.data.get().getType()); // this was "inherited" from o2 auto scope = o4.data.get().scope(); CHECK (!isnil(scope)); CHECK (GenNode("τ", Time(1,2,3,4)) == *scope); ++scope; CHECK (char('*') == scope->data.get()); ++scope; CHECK ("★" == scope->data.get()); ++scope; CHECK (luid == scope->data.get()); ++scope; CHECK (Time(920,0) == scope->data.get().end()); ++scope; auto spam = *scope; CHECK (!++scope); CHECK ("ham" == spam.data.get().getType()); CHECK (spam.contains ("eggs")); // but while o4 was based on o2, // adding all the additional contents didn't mutate o2 CHECK (isnil(o2.data.get())); // special case: can create an (Attribute) GenNode with specifically crafted ID idi::EntryID veryspecialID{"quasi niente"}; auto o5 = MakeRec().genNode(veryspecialID); CHECK (o5 != MakeRec().genNode()); CHECK (o5 != MakeRec().genNode("quasi niente")); CHECK (o5 == MakeRec().genNode(veryspecialID)); CHECK (name(o5) == "quasi_niente"); // Note: EntryID sanitised the string CHECK (o5.idi == veryspecialID); } void symbolReference() { GenNode ham = MakeRec().type("spam").attrib("τ", Time(23,42)).genNode("egg bacon sausage and spam"); GenNode::ID hamID(ham); CHECK (hamID == ham.idi); CHECK (hamID.getSym() == ham.idi.getSym()); CHECK (hamID.getHash() == ham.idi.getHash()); CHECK (contains (string(hamID), "spam")); // Lovely spam! Ref ref1("egg bacon sausage and spam"); // empty placeholder Ref ref2(ham); CHECK (ref1.idi == ham.idi); CHECK (ref2.idi == ham.idi); // can stand-in for the original Record... Rec& hamRef = ham.data.get(); CHECK (isSameObject (hamRef, ref2.data.get())); VERIFY_ERROR (BOTTOM_VALUE, ref1.data.get()); RecRef rr1 = ref1.data.get(); RecRef rr2 = ref2.data.get(); CHECK ( isnil(rr1)); CHECK (!isnil(rr2)); Rec& ham_ref = rr2; CHECK (isSameObject(hamRef, ham_ref)); CHECK (isSameObject(hamRef, *rr2.get())); // pre-defined special ref-tokens CHECK ("_END_" == name(Ref::END)); CHECK ("_THIS_" == name(Ref::THIS)); CHECK ("_CHILD_" == name(Ref::CHILD)); CHECK ("_ATTRIBS_" == name(Ref::ATTRIBS)); CHECK (isnil (Ref::END.data.get())); CHECK (isnil (Ref::THIS.data.get())); CHECK (isnil (Ref::CHILD.data.get())); CHECK (isnil (Ref::ATTRIBS.data.get())); } void sequenceIteration() { GenNode n = MakeRec() .scope('*' // a char node ,"★" // a string node , PI // a double value ,MakeRec().type("ham") .scope("eggs","spam","spam") .genNode("spam") // a spam object ,TimeSpan(Time::ZERO, FSecs(23,25)) // a time span ,int64_t(42)) // long value .attrib("hasSpam", true) // boolean Attribute .genNode("baked beans"); // build Node from named Record cout << "--spam--"<idi.getSym()); // initially the Record itself is exposed CHECK (Rec::TYPE_NIL == iter->data.get().getType()); ++iter; CHECK (2 == iter.level()); // delve into the contents, CHECK ("hasSpam" == iter->idi.getSym()); // ...starting with the attribute(s) CHECK (true == iter->data.get()); CHECK ("GenNode-ID(\"hasSpam\")-DataCap|«bool»|true" == string(*iter)); ++iter; CHECK (!iter->isNamed()); // contents of the object's scope CHECK ('*' == iter->data.get()); ++iter; CHECK (!iter->isNamed()); CHECK ("★" == iter->data.get()); ++iter; CHECK (!iter->isNamed()); CHECK (almostEqual (PI, iter->data.get())); ++iter; CHECK ("spam" == iter->idi.getSym()); // the nested object is first exposed as a whole CHECK ("ham" == iter->data.get().getType()); ++iter; CHECK (3 == iter.level()); CHECK ("eggs" == iter->data.get()); // contents of the nested ("spam") object's scope ++iter; CHECK ("spam" == iter->data.get()); ++iter; CHECK ("spam" == iter->data.get()); CHECK (3 == iter.level()); ++iter; CHECK (2 == iter.level()); // decreasing level indicates we left nested scope CHECK (!iter->isNamed()); // next item in the enclosing scope CHECK ("0:00:00.000≺920ms≻" == string(iter->data.get())); ++iter; CHECK (!iter->isNamed()); CHECK (42 == iter->data.get()); CHECK (2 == iter.level()); ++iter; // nothing more on top level beyond the initial Record CHECK (0 == iter.level()); CHECK (isnil (iter)); // another kind of iteration: shallow child data sequence // note: exposing the DataCap of each child auto child = childData(n); CHECK (!isnil (child)); CHECK ('*' == child->get()); ++child; CHECK ("★" == child->get()); ++child; CHECK (almostEqual (PI, child->get())); ++child; CHECK ("ham" == child->get().getType()); CHECK ("eggs" == child->get().child(0).data.get()); ++child; CHECK (TimeSpan(Time::ZERO, FSecs(23,25)) == child->get()); ++child; CHECK (42 == child->get()); ++child; CHECK (isnil (child)); CHECK (n.hasChildren()); CHECK (not GenNode{42}.hasChildren()); } void equalityMatch() { int i1 = 64; GenNode ni1(i1); int i2 = 126; GenNode ni2(i2); int64_t l1 = 64; GenNode nl1(l1); int64_t l2 = 126; GenNode nl2(l2); short r1 = 64; GenNode nr1(r1); short r2 = 126; GenNode nr2(r2); double d1 = 64; GenNode nd1(d1); double d2 = 126; GenNode nd2(d2); char c1 = '@'; GenNode nc1(c1); char c2 = '~'; GenNode nc2(c2); bool b1 = true; GenNode nb1(b1); bool b2 = false; GenNode nb2(b2); string s1 = ""; GenNode ns1(s1); string s2 = "↯"; GenNode ns2(s2); time::Time t1 = randTime(); GenNode nt1(t1); time::Time t2(-t1); GenNode nt2(t2); time::Offset to1(t1); GenNode nto1(to1); time::Offset to2(t2); GenNode nto2(to2); time::Duration td1(to2); GenNode ntd1(td1); time::Duration td2(to2*2); GenNode ntd2(td2); time::TimeSpan ts1(t1, td1); GenNode nts1(ts1); time::TimeSpan ts2(t2, td2); GenNode nts2(ts2); hash::LuidH h1; GenNode nh1(h1); hash::LuidH h2; GenNode nh2(h2); Rec spam1({GenNode("ham", "eggs")}); GenNode rec1(spam1); Rec spam2(MakeRec(spam1).type("spam")); GenNode rec2(spam2); RecRef recRef1(spam1); Ref ref1(rec1); RecRef recRef2(spam2); Ref ref2(rec2); // NOTE: same ID as referee CHECK (ni1 == ni1); CHECK (ni2 == ni2); CHECK (nl1 == nl1); CHECK (nl2 == nl2); CHECK (nr1 == nr1); CHECK (nr2 == nr2); CHECK (nd1 == nd1); CHECK (nd2 == nd2); CHECK (nc1 == nc1); CHECK (nc2 == nc2); CHECK (nb1 == nb1); CHECK (nb2 == nb2); CHECK (ns1 == ns1); CHECK (ns2 == ns2); CHECK (nt1 == nt1 ); CHECK (nt2 == nt2 ); CHECK (nto1 == nto1); CHECK (nto2 == nto2); CHECK (ntd1 == ntd1); CHECK (ntd2 == ntd2); CHECK (nts1 == nts1); CHECK (nts2 == nts2); CHECK (nh1 == nh1 ); CHECK (nh2 == nh2 ); CHECK (rec1 == rec1); CHECK (rec2 == rec2); CHECK (ref1 == ref1); CHECK (ref2 == ref2); CHECK (ni1 != ni2); CHECK (ni2 != ni1); CHECK (nl1 != nl2); CHECK (nl2 != nl1); CHECK (nr1 != nr2); CHECK (nr2 != nr1); CHECK (nd1 != nd2); CHECK (nd2 != nd1); CHECK (nc1 != nc2); CHECK (nc2 != nc1); CHECK (nb1 != nb2); CHECK (nb2 != nb1); CHECK (ns1 != ns2); CHECK (ns2 != ns1); CHECK (nt1 != nt2 ); CHECK (nt2 != nt1 ); CHECK (nto1 != nto2); CHECK (nto2 != nto1); CHECK (ntd1 != ntd2); CHECK (ntd2 != ntd1); CHECK (nts1 != nts2); CHECK (nts2 != nts1); CHECK (nh1 != nh2 ); CHECK (nh2 != nh1 ); CHECK (rec1 != rec2); CHECK (rec2 != rec1); CHECK (ref1 != ref2); CHECK (ref2 != ref1); CHECK (ni1 != ni2); CHECK (ni2 != ni1); CHECK (ni1 != nl1); CHECK (nl1 != ni1); CHECK (ni1 != nl2); CHECK (nl2 != ni1); CHECK (ni1 != nr1); CHECK (nr1 != ni1); CHECK (ni1 != nr2); CHECK (nr2 != ni1); CHECK (ni1 != nd1); CHECK (nd1 != ni1); CHECK (ni1 != nd2); CHECK (nd2 != ni1); CHECK (ni1 != nc1); CHECK (nc1 != ni1); CHECK (ni1 != nc2); CHECK (nc2 != ni1); CHECK (ni1 != nb1); CHECK (nb1 != ni1); CHECK (ni1 != nb2); CHECK (nb2 != ni1); CHECK (ni1 != ns1); CHECK (ns1 != ni1); CHECK (ni1 != ns2); CHECK (ns2 != ni1); CHECK (ni1 != nt1 ); CHECK (nt1 != ni1); CHECK (ni1 != nt2 ); CHECK (nt2 != ni1); CHECK (ni1 != nto1); CHECK (nto1 != ni1); CHECK (ni1 != nto2); CHECK (nto2 != ni1); CHECK (ni1 != ntd1); CHECK (ntd1 != ni1); CHECK (ni1 != ntd2); CHECK (ntd2 != ni1); CHECK (ni1 != nts1); CHECK (nts1 != ni1); CHECK (ni1 != nts2); CHECK (nts2 != ni1); CHECK (ni1 != nh1 ); CHECK (nh1 != ni1); CHECK (ni1 != nh2 ); CHECK (nh2 != ni1); CHECK (ni1 != rec1); CHECK (rec1 != ni1); CHECK (ni1 != rec2); CHECK (rec2 != ni1); CHECK (ni1 != ref1); CHECK (ref1 != ni1); CHECK (ni1 != ref2); CHECK (ref2 != ni1); CHECK (ni2 != nl1); CHECK (nl1 != ni2); CHECK (ni2 != nl2); CHECK (nl2 != ni2); CHECK (ni2 != nr1); CHECK (nr1 != ni2); CHECK (ni2 != nr2); CHECK (nr2 != ni2); CHECK (ni2 != nd1); CHECK (nd1 != ni2); CHECK (ni2 != nd2); CHECK (nd2 != ni2); CHECK (ni2 != nc1); CHECK (nc1 != ni2); CHECK (ni2 != nc2); CHECK (nc2 != ni2); CHECK (ni2 != nb1); CHECK (nb1 != ni2); CHECK (ni2 != nb2); CHECK (nb2 != ni2); CHECK (ni2 != ns1); CHECK (ns1 != ni2); CHECK (ni2 != ns2); CHECK (ns2 != ni2); CHECK (ni2 != nt1 ); CHECK (nt1 != ni2); CHECK (ni2 != nt2 ); CHECK (nt2 != ni2); CHECK (ni2 != nto1); CHECK (nto1 != ni2); CHECK (ni2 != nto2); CHECK (nto2 != ni2); CHECK (ni2 != ntd1); CHECK (ntd1 != ni2); CHECK (ni2 != ntd2); CHECK (ntd2 != ni2); CHECK (ni2 != nts1); CHECK (nts1 != ni2); CHECK (ni2 != nts2); CHECK (nts2 != ni2); CHECK (ni2 != nh1 ); CHECK (nh1 != ni2); CHECK (ni2 != nh2 ); CHECK (nh2 != ni2); CHECK (ni2 != rec1); CHECK (rec1 != ni2); CHECK (ni2 != rec2); CHECK (rec2 != ni2); CHECK (ni2 != ref1); CHECK (ref1 != ni2); CHECK (ni2 != ref2); CHECK (ref2 != ni2); CHECK (nl1 != nl2); CHECK (nl2 != nl1); CHECK (nl1 != nr1); CHECK (nr1 != nl1); CHECK (nl1 != nr2); CHECK (nr2 != nl1); CHECK (nl1 != nd1); CHECK (nd1 != nl1); CHECK (nl1 != nd2); CHECK (nd2 != nl1); CHECK (nl1 != nc1); CHECK (nc1 != nl1); CHECK (nl1 != nc2); CHECK (nc2 != nl1); CHECK (nl1 != nb1); CHECK (nb1 != nl1); CHECK (nl1 != nb2); CHECK (nb2 != nl1); CHECK (nl1 != ns1); CHECK (ns1 != nl1); CHECK (nl1 != ns2); CHECK (ns2 != nl1); CHECK (nl1 != nt1 ); CHECK (nt1 != nl1); CHECK (nl1 != nt2 ); CHECK (nt2 != nl1); CHECK (nl1 != nto1); CHECK (nto1 != nl1); CHECK (nl1 != nto2); CHECK (nto2 != nl1); CHECK (nl1 != ntd1); CHECK (ntd1 != nl1); CHECK (nl1 != ntd2); CHECK (ntd2 != nl1); CHECK (nl1 != nts1); CHECK (nts1 != nl1); CHECK (nl1 != nts2); CHECK (nts2 != nl1); CHECK (nl1 != nh1 ); CHECK (nh1 != nl1); CHECK (nl1 != nh2 ); CHECK (nh2 != nl1); CHECK (nl1 != rec1); CHECK (rec1 != nl1); CHECK (nl1 != rec2); CHECK (rec2 != nl1); CHECK (nl1 != ref1); CHECK (ref1 != nl1); CHECK (nl1 != ref2); CHECK (ref2 != nl1); CHECK (nl2 != nr1); CHECK (nr1 != nl2); CHECK (nl2 != nr2); CHECK (nr2 != nl2); CHECK (nl2 != nd1); CHECK (nd1 != nl2); CHECK (nl2 != nd2); CHECK (nd2 != nl2); CHECK (nl2 != nc1); CHECK (nc1 != nl2); CHECK (nl2 != nc2); CHECK (nc2 != nl2); CHECK (nl2 != nb1); CHECK (nb1 != nl2); CHECK (nl2 != nb2); CHECK (nb2 != nl2); CHECK (nl2 != ns1); CHECK (ns1 != nl2); CHECK (nl2 != ns2); CHECK (ns2 != nl2); CHECK (nl2 != nt1 ); CHECK (nt1 != nl2); CHECK (nl2 != nt2 ); CHECK (nt2 != nl2); CHECK (nl2 != nto1); CHECK (nto1 != nl2); CHECK (nl2 != nto2); CHECK (nto2 != nl2); CHECK (nl2 != ntd1); CHECK (ntd1 != nl2); CHECK (nl2 != ntd2); CHECK (ntd2 != nl2); CHECK (nl2 != nts1); CHECK (nts1 != nl2); CHECK (nl2 != nts2); CHECK (nts2 != nl2); CHECK (nl2 != nh1 ); CHECK (nh1 != nl2); CHECK (nl2 != nh2 ); CHECK (nh2 != nl2); CHECK (nl2 != rec1); CHECK (rec1 != nl2); CHECK (nl2 != rec2); CHECK (rec2 != nl2); CHECK (nl2 != ref1); CHECK (ref1 != nl2); CHECK (nl2 != ref2); CHECK (ref2 != nl2); CHECK (nr1 != nr2); CHECK (nr2 != nr1); CHECK (nr1 != nd1); CHECK (nd1 != nr1); CHECK (nr1 != nd2); CHECK (nd2 != nr1); CHECK (nr1 != nc1); CHECK (nc1 != nr1); CHECK (nr1 != nc2); CHECK (nc2 != nr1); CHECK (nr1 != nb1); CHECK (nb1 != nr1); CHECK (nr1 != nb2); CHECK (nb2 != nr1); CHECK (nr1 != ns1); CHECK (ns1 != nr1); CHECK (nr1 != ns2); CHECK (ns2 != nr1); CHECK (nr1 != nt1 ); CHECK (nt1 != nr1); CHECK (nr1 != nt2 ); CHECK (nt2 != nr1); CHECK (nr1 != nto1); CHECK (nto1 != nr1); CHECK (nr1 != nto2); CHECK (nto2 != nr1); CHECK (nr1 != ntd1); CHECK (ntd1 != nr1); CHECK (nr1 != ntd2); CHECK (ntd2 != nr1); CHECK (nr1 != nts1); CHECK (nts1 != nr1); CHECK (nr1 != nts2); CHECK (nts2 != nr1); CHECK (nr1 != nh1 ); CHECK (nh1 != nr1); CHECK (nr1 != nh2 ); CHECK (nh2 != nr1); CHECK (nr1 != rec1); CHECK (rec1 != nr1); CHECK (nr1 != rec2); CHECK (rec2 != nr1); CHECK (nr1 != ref1); CHECK (ref1 != nr1); CHECK (nr1 != ref2); CHECK (ref2 != nr1); CHECK (nr2 != nd1); CHECK (nd1 != nr2); CHECK (nr2 != nd2); CHECK (nd2 != nr2); CHECK (nr2 != nc1); CHECK (nc1 != nr2); CHECK (nr2 != nc2); CHECK (nc2 != nr2); CHECK (nr2 != nb1); CHECK (nb1 != nr2); CHECK (nr2 != nb2); CHECK (nb2 != nr2); CHECK (nr2 != ns1); CHECK (ns1 != nr2); CHECK (nr2 != ns2); CHECK (ns2 != nr2); CHECK (nr2 != nt1 ); CHECK (nt1 != nr2); CHECK (nr2 != nt2 ); CHECK (nt2 != nr2); CHECK (nr2 != nto1); CHECK (nto1 != nr2); CHECK (nr2 != nto2); CHECK (nto2 != nr2); CHECK (nr2 != ntd1); CHECK (ntd1 != nr2); CHECK (nr2 != ntd2); CHECK (ntd2 != nr2); CHECK (nr2 != nts1); CHECK (nts1 != nr2); CHECK (nr2 != nts2); CHECK (nts2 != nr2); CHECK (nr2 != nh1 ); CHECK (nh1 != nr2); CHECK (nr2 != nh2 ); CHECK (nh2 != nr2); CHECK (nr2 != rec1); CHECK (rec1 != nr2); CHECK (nr2 != rec2); CHECK (rec2 != nr2); CHECK (nr2 != ref1); CHECK (ref1 != nr2); CHECK (nr2 != ref2); CHECK (ref2 != nr2); CHECK (nd1 != nd2); CHECK (nd2 != nd1); CHECK (nd1 != nc1); CHECK (nc1 != nd1); CHECK (nd1 != nc2); CHECK (nc2 != nd1); CHECK (nd1 != nb1); CHECK (nb1 != nd1); CHECK (nd1 != nb2); CHECK (nb2 != nd1); CHECK (nd1 != ns1); CHECK (ns1 != nd1); CHECK (nd1 != ns2); CHECK (ns2 != nd1); CHECK (nd1 != nt1 ); CHECK (nt1 != nd1); CHECK (nd1 != nt2 ); CHECK (nt2 != nd1); CHECK (nd1 != nto1); CHECK (nto1 != nd1); CHECK (nd1 != nto2); CHECK (nto2 != nd1); CHECK (nd1 != ntd1); CHECK (ntd1 != nd1); CHECK (nd1 != ntd2); CHECK (ntd2 != nd1); CHECK (nd1 != nts1); CHECK (nts1 != nd1); CHECK (nd1 != nts2); CHECK (nts2 != nd1); CHECK (nd1 != nh1 ); CHECK (nh1 != nd1); CHECK (nd1 != nh2 ); CHECK (nh2 != nd1); CHECK (nd1 != rec1); CHECK (rec1 != nd1); CHECK (nd1 != rec2); CHECK (rec2 != nd1); CHECK (nd1 != ref1); CHECK (ref1 != nd1); CHECK (nd1 != ref2); CHECK (ref2 != nd1); CHECK (nd2 != nc1); CHECK (nc1 != nd2); CHECK (nd2 != nc2); CHECK (nc2 != nd2); CHECK (nd2 != nb1); CHECK (nb1 != nd2); CHECK (nd2 != nb2); CHECK (nb2 != nd2); CHECK (nd2 != ns1); CHECK (ns1 != nd2); CHECK (nd2 != ns2); CHECK (ns2 != nd2); CHECK (nd2 != nt1 ); CHECK (nt1 != nd2); CHECK (nd2 != nt2 ); CHECK (nt2 != nd2); CHECK (nd2 != nto1); CHECK (nto1 != nd2); CHECK (nd2 != nto2); CHECK (nto2 != nd2); CHECK (nd2 != ntd1); CHECK (ntd1 != nd2); CHECK (nd2 != ntd2); CHECK (ntd2 != nd2); CHECK (nd2 != nts1); CHECK (nts1 != nd2); CHECK (nd2 != nts2); CHECK (nts2 != nd2); CHECK (nd2 != nh1 ); CHECK (nh1 != nd2); CHECK (nd2 != nh2 ); CHECK (nh2 != nd2); CHECK (nd2 != rec1); CHECK (rec1 != nd2); CHECK (nd2 != rec2); CHECK (rec2 != nd2); CHECK (nd2 != ref1); CHECK (ref1 != nd2); CHECK (nd2 != ref2); CHECK (ref2 != nd2); CHECK (nc1 != nc2); CHECK (nc2 != nc1); CHECK (nc1 != nb1); CHECK (nb1 != nc1); CHECK (nc1 != nb2); CHECK (nb2 != nc1); CHECK (nc1 != ns1); CHECK (ns1 != nc1); CHECK (nc1 != ns2); CHECK (ns2 != nc1); CHECK (nc1 != nt1 ); CHECK (nt1 != nc1); CHECK (nc1 != nt2 ); CHECK (nt2 != nc1); CHECK (nc1 != nto1); CHECK (nto1 != nc1); CHECK (nc1 != nto2); CHECK (nto2 != nc1); CHECK (nc1 != ntd1); CHECK (ntd1 != nc1); CHECK (nc1 != ntd2); CHECK (ntd2 != nc1); CHECK (nc1 != nts1); CHECK (nts1 != nc1); CHECK (nc1 != nts2); CHECK (nts2 != nc1); CHECK (nc1 != nh1 ); CHECK (nh1 != nc1); CHECK (nc1 != nh2 ); CHECK (nh2 != nc1); CHECK (nc1 != rec1); CHECK (rec1 != nc1); CHECK (nc1 != rec2); CHECK (rec2 != nc1); CHECK (nc1 != ref1); CHECK (ref1 != nc1); CHECK (nc1 != ref2); CHECK (ref2 != nc1); CHECK (nc2 != nb1); CHECK (nb1 != nc2); CHECK (nc2 != nb2); CHECK (nb2 != nc2); CHECK (nc2 != ns1); CHECK (ns1 != nc2); CHECK (nc2 != ns2); CHECK (ns2 != nc2); CHECK (nc2 != nt1 ); CHECK (nt1 != nc2); CHECK (nc2 != nt2 ); CHECK (nt2 != nc2); CHECK (nc2 != nto1); CHECK (nto1 != nc2); CHECK (nc2 != nto2); CHECK (nto2 != nc2); CHECK (nc2 != ntd1); CHECK (ntd1 != nc2); CHECK (nc2 != ntd2); CHECK (ntd2 != nc2); CHECK (nc2 != nts1); CHECK (nts1 != nc2); CHECK (nc2 != nts2); CHECK (nts2 != nc2); CHECK (nc2 != nh1 ); CHECK (nh1 != nc2); CHECK (nc2 != nh2 ); CHECK (nh2 != nc2); CHECK (nc2 != rec1); CHECK (rec1 != nc2); CHECK (nc2 != rec2); CHECK (rec2 != nc2); CHECK (nc2 != ref1); CHECK (ref1 != nc2); CHECK (nc2 != ref2); CHECK (ref2 != nc2); CHECK (nb1 != nb2); CHECK (nb2 != nb1); CHECK (nb1 != ns1); CHECK (ns1 != nb1); CHECK (nb1 != ns2); CHECK (ns2 != nb1); CHECK (nb1 != nt1 ); CHECK (nt1 != nb1); CHECK (nb1 != nt2 ); CHECK (nt2 != nb1); CHECK (nb1 != nto1); CHECK (nto1 != nb1); CHECK (nb1 != nto2); CHECK (nto2 != nb1); CHECK (nb1 != ntd1); CHECK (ntd1 != nb1); CHECK (nb1 != ntd2); CHECK (ntd2 != nb1); CHECK (nb1 != nts1); CHECK (nts1 != nb1); CHECK (nb1 != nts2); CHECK (nts2 != nb1); CHECK (nb1 != nh1 ); CHECK (nh1 != nb1); CHECK (nb1 != nh2 ); CHECK (nh2 != nb1); CHECK (nb1 != rec1); CHECK (rec1 != nb1); CHECK (nb1 != rec2); CHECK (rec2 != nb1); CHECK (nb1 != ref1); CHECK (ref1 != nb1); CHECK (nb1 != ref2); CHECK (ref2 != nb1); CHECK (nb2 != ns1); CHECK (ns1 != nb2); CHECK (nb2 != ns2); CHECK (ns2 != nb2); CHECK (nb2 != nt1 ); CHECK (nt1 != nb2); CHECK (nb2 != nt2 ); CHECK (nt2 != nb2); CHECK (nb2 != nto1); CHECK (nto1 != nb2); CHECK (nb2 != nto2); CHECK (nto2 != nb2); CHECK (nb2 != ntd1); CHECK (ntd1 != nb2); CHECK (nb2 != ntd2); CHECK (ntd2 != nb2); CHECK (nb2 != nts1); CHECK (nts1 != nb2); CHECK (nb2 != nts2); CHECK (nts2 != nb2); CHECK (nb2 != nh1 ); CHECK (nh1 != nb2); CHECK (nb2 != nh2 ); CHECK (nh2 != nb2); CHECK (nb2 != rec1); CHECK (rec1 != nb2); CHECK (nb2 != rec2); CHECK (rec2 != nb2); CHECK (nb2 != ref1); CHECK (ref1 != nb2); CHECK (nb2 != ref2); CHECK (ref2 != nb2); CHECK (ns1 != nt2 ); CHECK (nt2 != ns1); CHECK (ns1 != nto1); CHECK (nto1 != ns1); CHECK (ns1 != nto2); CHECK (nto2 != ns1); CHECK (ns1 != ntd1); CHECK (ntd1 != ns1); CHECK (ns1 != ntd2); CHECK (ntd2 != ns1); CHECK (ns1 != nts1); CHECK (nts1 != ns1); CHECK (ns1 != nts2); CHECK (nts2 != ns1); CHECK (ns1 != nh1 ); CHECK (nh1 != ns1); CHECK (ns1 != nh2 ); CHECK (nh2 != ns1); CHECK (ns1 != rec1); CHECK (rec1 != ns1); CHECK (ns1 != rec2); CHECK (rec2 != ns1); CHECK (ns1 != ref1); CHECK (ref1 != ns1); CHECK (ns1 != ref2); CHECK (ref2 != ns1); CHECK (ns2 != nt1 ); CHECK (nt1 != ns2); CHECK (ns2 != nt2 ); CHECK (nt2 != ns2); CHECK (ns2 != nto1); CHECK (nto1 != ns2); CHECK (ns2 != nto2); CHECK (nto2 != ns2); CHECK (ns2 != ntd1); CHECK (ntd1 != ns2); CHECK (ns2 != ntd2); CHECK (ntd2 != ns2); CHECK (ns2 != nts1); CHECK (nts1 != ns2); CHECK (ns2 != nts2); CHECK (nts2 != ns2); CHECK (ns2 != nh1 ); CHECK (nh1 != ns2); CHECK (ns2 != nh2 ); CHECK (nh2 != ns2); CHECK (ns2 != rec1); CHECK (rec1 != ns2); CHECK (ns2 != rec2); CHECK (rec2 != ns2); CHECK (ns2 != ref1); CHECK (ref1 != ns2); CHECK (ns2 != ref2); CHECK (ref2 != ns2); CHECK (nt1 != nt2 ); CHECK (nt2 != nt1); CHECK (nt1 != nto1); CHECK (nto1 != nt1); CHECK (nt1 != nto2); CHECK (nto2 != nt1); CHECK (nt1 != ntd1); CHECK (ntd1 != nt1); CHECK (nt1 != ntd2); CHECK (ntd2 != nt1); CHECK (nt1 != nts1); CHECK (nts1 != nt1); CHECK (nt1 != nts2); CHECK (nts2 != nt1); CHECK (nt1 != nh1 ); CHECK (nh1 != nt1); CHECK (nt1 != nh2 ); CHECK (nh2 != nt1); CHECK (nt1 != rec1); CHECK (rec1 != nt1); CHECK (nt1 != rec2); CHECK (rec2 != nt1); CHECK (nt1 != ref1); CHECK (ref1 != nt1); CHECK (nt1 != ref2); CHECK (ref2 != nt1); CHECK (nt2 != nto1); CHECK (nto1 != nt2); CHECK (nt2 != nto2); CHECK (nto2 != nt2); CHECK (nt2 != ntd1); CHECK (ntd1 != nt2); CHECK (nt2 != ntd2); CHECK (ntd2 != nt2); CHECK (nt2 != nts1); CHECK (nts1 != nt2); CHECK (nt2 != nts2); CHECK (nts2 != nt2); CHECK (nt2 != nh1 ); CHECK (nh1 != nt2); CHECK (nt2 != nh2 ); CHECK (nh2 != nt2); CHECK (nt2 != rec1); CHECK (rec1 != nt2); CHECK (nt2 != rec2); CHECK (rec2 != nt2); CHECK (nt2 != ref1); CHECK (ref1 != nt2); CHECK (nt2 != ref2); CHECK (ref2 != nt2); CHECK (nto1 != nto2); CHECK (nto2 != nto1); CHECK (nto1 != ntd1); CHECK (ntd1 != nto1); CHECK (nto1 != ntd2); CHECK (ntd2 != nto1); CHECK (nto1 != nts1); CHECK (nts1 != nto1); CHECK (nto1 != nts2); CHECK (nts2 != nto1); CHECK (nto1 != nh1 ); CHECK (nh1 != nto1); CHECK (nto1 != nh2 ); CHECK (nh2 != nto1); CHECK (nto1 != rec1); CHECK (rec1 != nto1); CHECK (nto1 != rec2); CHECK (rec2 != nto1); CHECK (nto1 != ref1); CHECK (ref1 != nto1); CHECK (nto1 != ref2); CHECK (ref2 != nto1); CHECK (nto2 != ntd1); CHECK (ntd1 != nto2); CHECK (nto2 != ntd2); CHECK (ntd2 != nto2); CHECK (nto2 != nts1); CHECK (nts1 != nto2); CHECK (nto2 != nts2); CHECK (nts2 != nto2); CHECK (nto2 != nh1 ); CHECK (nh1 != nto2); CHECK (nto2 != nh2 ); CHECK (nh2 != nto2); CHECK (nto2 != rec1); CHECK (rec1 != nto2); CHECK (nto2 != rec2); CHECK (rec2 != nto2); CHECK (nto2 != ref1); CHECK (ref1 != nto2); CHECK (nto2 != ref2); CHECK (ref2 != nto2); CHECK (ntd1 != ntd2); CHECK (ntd2 != ntd1); CHECK (ntd1 != nts1); CHECK (nts1 != ntd1); CHECK (ntd1 != nts2); CHECK (nts2 != ntd1); CHECK (ntd1 != nh1 ); CHECK (nh1 != ntd1); CHECK (ntd1 != nh2 ); CHECK (nh2 != ntd1); CHECK (ntd1 != rec1); CHECK (rec1 != ntd1); CHECK (ntd1 != rec2); CHECK (rec2 != ntd1); CHECK (ntd1 != ref1); CHECK (ref1 != ntd1); CHECK (ntd1 != ref2); CHECK (ref2 != ntd1); CHECK (ntd2 != nts1); CHECK (nts1 != ntd2); CHECK (ntd2 != nts2); CHECK (nts2 != ntd2); CHECK (ntd2 != nh1 ); CHECK (nh1 != ntd2); CHECK (ntd2 != nh2 ); CHECK (nh2 != ntd2); CHECK (ntd2 != rec1); CHECK (rec1 != ntd2); CHECK (ntd2 != rec2); CHECK (rec2 != ntd2); CHECK (ntd2 != ref1); CHECK (ref1 != ntd2); CHECK (ntd2 != ref2); CHECK (ref2 != ntd2); CHECK (nts1 != nts2); CHECK (nts2 != nts1); CHECK (nts1 != nh1 ); CHECK (nh1 != nts1); CHECK (nts1 != nh2 ); CHECK (nh2 != nts1); CHECK (nts1 != rec1); CHECK (rec1 != nts1); CHECK (nts1 != rec2); CHECK (rec2 != nts1); CHECK (nts1 != ref1); CHECK (ref1 != nts1); CHECK (nts1 != ref2); CHECK (ref2 != nts1); CHECK (nts2 != nh1 ); CHECK (nh1 != nts2); CHECK (nts2 != nh2 ); CHECK (nh2 != nts2); CHECK (nts2 != rec1); CHECK (rec1 != nts2); CHECK (nts2 != rec2); CHECK (rec2 != nts2); CHECK (nts2 != ref1); CHECK (ref1 != nts2); CHECK (nts2 != ref2); CHECK (ref2 != nts2); CHECK (nh1 != nh2 ); CHECK (nh2 != nh1); CHECK (nh1 != rec1); CHECK (rec1 != nh1); CHECK (nh1 != rec2); CHECK (rec2 != nh1); CHECK (nh1 != ref1); CHECK (ref1 != nh1); CHECK (nh1 != ref2); CHECK (ref2 != nh1); CHECK (nh2 != rec1); CHECK (rec1 != nh2); CHECK (nh2 != rec2); CHECK (rec2 != nh2); CHECK (nh2 != ref1); CHECK (ref1 != nh2); CHECK (nh2 != ref2); CHECK (ref2 != nh2); CHECK (rec1 != rec2); CHECK (rec2 != rec1); CHECK (ref1 != ref2); CHECK (ref2 != ref1); // NOTE: special handling for record references… CHECK (rec1 == ref1); CHECK (ref1 == rec1); CHECK (rec1 != ref2); CHECK (ref2 != rec1); CHECK (rec2 != ref1); CHECK (ref1 != rec2); CHECK (rec2 == ref2); CHECK (ref2 == rec2); /* ----- equivalence match ----- */ // equivalence as object // equivalence on ID match // contained value equality CHECK (ni1 .matches(ni1 )); CHECK (ni1 .matches(ni1 .idi)); CHECK (ni1 .matches(i1 )); CHECK (ni2 .matches(ni2 )); CHECK (ni2 .matches(ni2 .idi)); CHECK (ni2 .matches(i2 )); CHECK (nl1 .matches(nl1 )); CHECK (nl1 .matches(nl1 .idi)); CHECK (nl1 .matches(l1 )); CHECK (nl2 .matches(nl2 )); CHECK (nl2 .matches(nl2 .idi)); CHECK (nl2 .matches(l2 )); CHECK (nr1 .matches(nr1 )); CHECK (nr1 .matches(nr1 .idi)); CHECK (nr1 .matches(r1 )); CHECK (nr2 .matches(nr2 )); CHECK (nr2 .matches(nr2 .idi)); CHECK (nr2 .matches(r2 )); CHECK (nd1 .matches(nd1 )); CHECK (nd1 .matches(nd1 .idi)); CHECK (nd1 .matches(d1 )); CHECK (nd2 .matches(nd2 )); CHECK (nd2 .matches(nd2 .idi)); CHECK (nd2 .matches(d2 )); CHECK (nc1 .matches(nc1 )); CHECK (nc1 .matches(nc1 .idi)); CHECK (nc1 .matches(c1 )); CHECK (nc2 .matches(nc2 )); CHECK (nc2 .matches(nc2 .idi)); CHECK (nc2 .matches(c2 )); CHECK (nb1 .matches(nb1 )); CHECK (nb1 .matches(nb1 .idi)); CHECK (nb1 .matches(b1 )); CHECK (nb2 .matches(nb2 )); CHECK (nb2 .matches(nb2 .idi)); CHECK (nb2 .matches(b2 )); CHECK (ns1 .matches(ns1 )); CHECK (ns1 .matches(ns1 .idi)); CHECK (ns1 .matches(s1 )); CHECK (ns2 .matches(ns2 )); CHECK (ns2 .matches(ns2 .idi)); CHECK (ns2 .matches(s2 )); CHECK (nt1 .matches(nt1 )); CHECK (nt1 .matches(nt1 .idi)); CHECK (nt1 .matches(t1 )); CHECK (nt2 .matches(nt2 )); CHECK (nt2 .matches(nt2 .idi)); CHECK (nt2 .matches(t2 )); CHECK (nto1.matches(nto1)); CHECK (nto1.matches(nto1.idi)); CHECK (nto1.matches(to1)); CHECK (nto2.matches(nto2)); CHECK (nto2.matches(nto2.idi)); CHECK (nto2.matches(to2)); CHECK (ntd1.matches(ntd1)); CHECK (ntd1.matches(ntd1.idi)); CHECK (ntd1.matches(td1)); CHECK (ntd2.matches(ntd2)); CHECK (ntd2.matches(ntd2.idi)); CHECK (ntd2.matches(td2)); CHECK (nts1.matches(nts1)); CHECK (nts1.matches(nts1.idi)); CHECK (nts1.matches(ts1)); CHECK (nts2.matches(nts2)); CHECK (nts2.matches(nts2.idi)); CHECK (nts2.matches(ts2)); CHECK (nh1 .matches(nh1 )); CHECK (nh1 .matches(nh1 .idi)); CHECK (nh1 .matches(h1 )); CHECK (nh2 .matches(nh2 )); CHECK (nh2 .matches(nh2 .idi)); CHECK (nh2 .matches(h2 )); CHECK (rec1.matches(rec1)); CHECK (rec1.matches(rec1.idi)); CHECK (rec1.matches(spam1)); CHECK (rec2.matches(rec2)); CHECK (rec2.matches(rec2.idi)); CHECK (rec2.matches(spam2)); CHECK (ref1.matches(ref1)); CHECK (ref1.matches(ref1.idi)); CHECK (ref1.matches(recRef1)); CHECK (ref2.matches(ref2)); CHECK (ref2.matches(ref2.idi)); CHECK (ref2.matches(recRef2)); // cross-match on equivalent payload data -------- CHECK (nl1.matches(i1)); CHECK (nr1.matches(i1)); CHECK (nd1.matches(i1)); CHECK (nc1.matches(i1)); CHECK (ni1.matches(l1)); CHECK (nr1.matches(l1)); CHECK (nd1.matches(l1)); CHECK (nc1.matches(l1)); CHECK (ni1.matches(r1)); CHECK (nl1.matches(r1)); CHECK (nd1.matches(r1)); CHECK (nc1.matches(r1)); CHECK (ni1.matches(d1)); CHECK (nl1.matches(d1)); CHECK (nr1.matches(d1)); CHECK (nc1.matches(d1)); CHECK (ni1.matches(c1)); CHECK (nl1.matches(c1)); CHECK (nr1.matches(c1)); CHECK (nd1.matches(c1)); CHECK (nl2.matches(i2)); CHECK (nr2.matches(i2)); CHECK (nd2.matches(i2)); CHECK (nc2.matches(i2)); CHECK (ni2.matches(l2)); CHECK (nr2.matches(l2)); CHECK (nd2.matches(l2)); CHECK (nc2.matches(l2)); CHECK (ni2.matches(r2)); CHECK (nl2.matches(r2)); CHECK (nd2.matches(r2)); CHECK (nc2.matches(r2)); CHECK (ni2.matches(d2)); CHECK (nl2.matches(d2)); CHECK (nr2.matches(d2)); CHECK (nc2.matches(d2)); CHECK (ni2.matches(c2)); CHECK (nl2.matches(c2)); CHECK (nr2.matches(c2)); CHECK (nd2.matches(c2)); CHECK (nto1.matches(t1 )); CHECK (nts1.matches(t1 )); CHECK (nt1.matches(to1)); CHECK (nts1.matches(to1)); CHECK (nt1.matches(ts1)); CHECK (nto1.matches(ts1)); CHECK (nto2.matches(t2 )); CHECK (nts2.matches(t2 )); CHECK (nt2.matches(to2)); CHECK (nts2.matches(to2)); CHECK (nt2.matches(ts2)); CHECK (nto2.matches(ts2)); CHECK (ns1.matches("")); CHECK (ns2.matches("↯")); CHECK (nc1.matches("@")); CHECK (nc2.matches("~")); // match due to references sharing the target's ID CHECK (rec1.matches(ref1.idi)); CHECK (ref1.matches(rec1.idi)); CHECK (rec2.matches(ref2.idi)); CHECK (ref2.matches(rec2.idi)); // some negative cases... CHECK (!ni1.matches(i2)); CHECK (!ni2.matches(i1)); CHECK (!ni1.matches(l2)); CHECK (!ni2.matches(l1)); CHECK (!ni1.matches(r2)); CHECK (!ni2.matches(r1)); CHECK (!ni1.matches(d2)); CHECK (!ni2.matches(d1)); CHECK (!ni1.matches(c2)); CHECK (!ni2.matches(c1)); CHECK (!nd1.matches(i2)); CHECK (!nd2.matches(i1)); CHECK (!nd1.matches(l2)); CHECK (!nd2.matches(l1)); CHECK (!nd1.matches(r2)); CHECK (!nd2.matches(r1)); CHECK (!nd1.matches(d2)); CHECK (!nd2.matches(d1)); CHECK (!nd1.matches(c2)); CHECK (!nd2.matches(c1)); // string match is literal CHECK (!ns1.matches(" ")); CHECK (!ns2.matches("↯ ")); GenNode copy(ni1); CHECK (copy == ni1); copy.data = 2*i1; CHECK (copy != ni1); CHECK (copy.idi == ni1.idi); CHECK (not copy.data.matchData(ni1.data)); // NOTE: "match" operation is shallow on records CHECK (copy.matches(ni1)); CHECK (ni1.matches(copy)); } /** @test simplified notation for access to nested record properties. * This is a somewhat questionable shorthand, insofar it allows to "probe" * the contents of a GenNode to some limited extent. Generally speaking, * we'd prefer if the code using GenNode operates based on precise * structural knowledge, instead of peeking into the data. */ void convenienceRecAccess() { GenNode n1(42); GenNode n2 = MakeRec().type("spam").genNode("eggs"); GenNode n3 = MakeRec().attrib("Ψ", Time(3,2,1)).genNode(); CHECK (not n1.isNamed()); CHECK ( n2.isNamed()); CHECK (not n3.isNamed()); CHECK (not n1.isNested()); CHECK ( n2.isNested()); CHECK ( n3.isNested()); CHECK (n1.data.recordType() == util::BOTTOM_INDICATOR); CHECK (n2.data.recordType() == "spam" ); CHECK (n3.data.recordType() == Rec::TYPE_NIL ); CHECK (not n1.hasAttribute("baked beans")); CHECK (not n2.hasAttribute("baked beans")); CHECK (not n3.hasAttribute("baked beans")); CHECK (not n1.hasAttribute("Ψ")); CHECK (not n2.hasAttribute("Ψ")); CHECK ( n3.hasAttribute("Ψ")); CHECK (not n1.retrieveAttribute("Ψ")); CHECK (not n2.retrieveAttribute("Ψ")); CHECK (not n3.retrieveAttribute("Ψ")); CHECK (not n1.retrieveAttribute