/* TestEventLog(Test) - helper for event registration and verification 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/test/test-helper.hpp" #include "lib/format-util.hpp" #include "lib/test/event-log.hpp" #include "lib/error.hpp" #include "lib/util.hpp" #include #include using util::join; using util::isnil; using lumiera::error::LUMIERA_ERROR_ASSERTION; using std::string; using std::cout; using std::endl; namespace lib { namespace test{ namespace test{ template class Wrmrmpft { T tt_; }; struct Murpf { }; /***********************************************************//** * @test verify a logging facility, which can be used to ensure * some events happened while running test code. * * @see event-log.hpp */ class TestEventLog_test : public Test { void run (Arg) { verify_simpleUsage(); verify_backwardMatch(); verify_negatedMatch(); verify_logJoining(); verify_callLogging(); verify_eventLogging(); } void verify_simpleUsage () { EventLog log(this); CHECK (isnil (log)); log.event("α"); log.event("β"); CHECK (!isnil(log)); CHECK (log.verify("α")); CHECK (log.verify("β")); CHECK (not log.verify("γ")); CHECK (log.verify("α").before("β")); CHECK (not log.verify("β").before("α")); CHECK (join(log) == "Rec(EventLogHeader| ID = "+idi::instanceTypeID(this)+" ), " + "Rec(event|{α}), " + "Rec(event|{β})"); } void verify_backwardMatch () { EventLog log("baked beans"); log.event("spam"); log.event("ham"); CHECK (log.verify("ham").after("spam").after("beans")); CHECK (log.verify("ham").after("beans").before("spam").before("ham")); CHECK (not log.verify("spam").after("beans").after("ham")); } void verify_negatedMatch () { EventLog log("eggs"); log.event("spam"); log.event("ham"); log.event("spam"); CHECK (log.ensureNot("baked beans")); CHECK (log.ensureNot("ham").before("eggs")); CHECK (log.ensureNot("spam").after("spam").before("eggs")); CHECK (not log.ensureNot("spam").before("spam").after("eggs").before("ham")); } void verify_logJoining () { EventLog log1("spam"); EventLog log2("ham"); log1.event("baked beans"); log2.event("eggs"); CHECK (log1.verify("spam").before("baked beans")); CHECK (log2.verify("ham").before("eggs")); CHECK (log1.ensureNot("ham")); CHECK (log1.ensureNot("eggs")); CHECK (log2.ensureNot("spam")); CHECK (log2.ensureNot("baked beans")); EventLog copy(log2); copy.event("bacon"); CHECK (copy.verify("ham").before("eggs").before("bacon")); CHECK (log2.verify("ham").before("eggs").before("bacon")); CHECK (log1.ensureNot("bacon")); CHECK (log1 != log2); CHECK (copy == log2); log2.joinInto(log1); CHECK (log1 == log2); CHECK (copy != log2); CHECK (log1.verify("logJoin|{ham}").after("baked beans")); CHECK (log1.verify("logJoin|{ham}").after("EventLogHeader| ID = ham").before("eggs").before("bacon").before("logJoin")); log2.event("sausage"); CHECK (log1.verify("sausage").after("logJoin").after("spam")); CHECK (copy.ensureNot("logJoin")); CHECK (copy.ensureNot("sausage")); CHECK (copy.verify("joined|{spam}").after("EventLogHeader")); copy.event("spam tomato"); CHECK (log1.ensureNot("spam tomato")); CHECK (log2.ensureNot("spam tomato")); CHECK (copy.verify("joined|{spam}").before("spam tomato")); CHECK (join(log1) == string( "Rec(EventLogHeader| ID = spam ), " "Rec(event|{baked beans}), " "Rec(EventLogHeader| ID = ham ), " "Rec(event|{eggs}), " "Rec(event|{bacon}), " "Rec(logJoin|{ham}), " "Rec(event|{sausage})")); CHECK (join(copy) == string( "Rec(EventLogHeader| ID = ham ), " "Rec(joined|{spam}), " "Rec(event|{spam tomato})")); } void verify_callLogging () { EventLog log("funCall"); log.call (this, "fun1"); log.call ("some", "fun2"); log.call ("more", "fun3", "facts", 3.2,1); CHECK(log.verify("fun1").before("fun2").before("fun3")); CHECK (join(log) == string( "Rec(EventLogHeader| ID = funCall ), " "Rec(call| fun = fun1, this = "+idi::instanceTypeID(this)+" ), " "Rec(call| fun = fun2, this = some ), " "Rec(call| fun = fun3, this = more |{facts, 3.2, 1})")); CHECK (log.verifyCall("fun1")); CHECK (log.verifyCall("fun2")); CHECK (log.verifyCall("fun3")); CHECK (log.verifyCall("fun")); CHECK (log.verifyCall("fun").after("fun").after("fun")); CHECK (log.ensureNot("fun").after("fun").after("fun2")); CHECK (log.verifyCall("fun3").arg("facts", 3.2, 1)); CHECK (log.verifyCall("fun3").arg(string("facts"), 3.2f, int64_t(1))); CHECK (log.verifyCall("fun3").arg("facts", "3.2", "1")); CHECK (log.ensureNot("fun").arg(" facts ", "3.20", "1L")); CHECK (log.verifyCall("fun1").arg()); CHECK (log.verifyCall("fun2").arg()); CHECK (log.verify("fun").arg().before("fun").arg("facts", 3.2, 1)); CHECK (log.verify("fun").on(this)); CHECK (log.verify("fun").on("some")); CHECK (log.verify("fun").on("more")); CHECK (log.verify("fun").on("more").on("more")); CHECK (log.ensureNot("fun").on("some").on("more")); CHECK (log.verify("fun").on("some").arg()); CHECK (log.ensureNot("fun").arg().on("more")); CHECK (log.ensureNot("fun").on("some").arg("facts", "3.2", "1")); CHECK (log.verifyCall("fun").arg("facts", "3.2", "1").on("more")); } void verify_eventLogging () { EventLog log("event trace"); log.event("no","fun"); log.call("some","fun"); CHECK (log.verify("fun").before("fun")); CHECK (log.verify("no").before("some")); CHECK (log.verifyEvent("fun").beforeCall("fun").on("some")); CHECK (!log.verifyEvent("fun").after("some")); CHECK (log.verifyEvent("no","fun")); CHECK (log.verifyEvent("fun").id("no")); CHECK (log.verify("no").arg("fun")); CHECK (join(log) == string( "Rec(EventLogHeader| ID = event trace ), " "Rec(event| ID = no |{fun}), " "Rec(call| fun = fun, this = some |{})")); } void verify_genericLogging () { EventLog log("theHog"); log.note ("type=some","ID=weird","stuff"); log.warn ("danger"); log.error ("horrible"); log.fatal ("destiny"); log.create ("something"); log.destroy ("everything"); CHECK (log.verify("theHog") .before("stuff") .before("danger") .before("horrible") .before("destiny") .before("something") .before("everything")); CHECK (log.verify("ID").type("EventLogHeader") .before("weird").type("some") .before("danger").type("warn") .before("horrible").type("error") .before("destiny").type("fatal") .before("something").type("create") .before("everything").type("destroy")); CHECK (log.verify("some").attrib("ID","weird").arg("stuff")); // NOTE: there is some built-in leeway in event-matching... CHECK (log.verifyEvent("horrible").beforeEvent("something").beforeEvent("everything")); CHECK (!log.verifyEvent("stuff")); // not every entry type is an event by default CHECK (!log.verifyEvent("danger")); // warning is not an event by default CHECK (log.verifyEvent("some","stuff")); // but the classifier-param matches on the type CHECK (log.verifyEvent("weird","stuff")); CHECK (log.verifyEvent("warn","danger")); CHECK (log.verifyEvent("fatal","destiny")); CHECK (log.verifyEvent("destroy","everything")); CHECK (join(log) == string( "Rec(EventLogHeader| ID = theHog ), " "Rec(some| ID = weird |{struff}), " "Rec(warn|{danger}), " "Rec(error|{horrible}), " "Rec(fatal|{destiny}), " "Rec(create|{something}), " "Rec(destroy|{everything})")); } /** @test prints TODO */ void checkTODO () { #if false ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #975 log.verifyEvent("ctor"); log.verify("ctor").arg("dummy"); CHECK ("dummy" == log.getID().getSym()); CHECK ("ID-dummy" = string(log.getID())); VERIFY_ERROR (ASSERTION, log.verifyCall("reset")); log.reset(); log.verify("reset"); log.verifyCall("reset"); log.verifyEvent("reset"); log.verify("reset").after("ctor"); log.verify("ctor").before("reset"); VERIFY_ERROR (ASSERTION, log.verify("reset").before("ctor")); VERIFY_ERROR (ASSERTION, log.verify("ctor").after("reset")); log.verify("reset").before("reset"); log.verify("reset").beforeEvent("reset"); log.verifyCall("reset").before("reset"); log.verifyCall("reset").beforeEvent("reset"); VERIFY_ERROR (ASSERTION, log.verifyCall("reset").afterCall("reset")); VERIFY_ERROR (ASSERTION, log.verifyCall("reset").afterEvent("reset")); VERIFY_ERROR (ASSERTION, log.verifyEvent("reset").afterEvent("reset")); CHECK (!log.isTouched()); CHECK (!log.isExpanded()); log.noteMsg("dolorem ipsum quia dolor sit amet consectetur adipisci velit."); log.verifyNote("Msg"); log.verifyCall("noteMsg"); log.verifyCall("noteMsg").arg("lorem ipsum"); log.verifyCall("noteMsg").argMatch("dolor.+dolor\\s+"); log.verifyMatch("Rec\\(note.+kind = Msg.+msg = dolorem ipsum"); EventLog log = log.getLog(); log.verify("ctor") .before("reset") .before("lorem ipsum"); MockElm foo("foo"), bar; foo.verify("ctor").arg("foo"); bar.verify("ctor").arg(); bar.ensureNot("foo"); log.ensureNot("foo"); log.ensureNot("foo"); VERIFY_ERROR (ASSERTION, foo.ensureNot("foo")); log.joinInto(bar).joinInto(foo); log.verifyEvent("logJoin").arg(bar.getID()) .beforeEvent("logJoin").arg("foo"); log.verifyEvent("logJoin").arg(bar.getID()) .beforeEvent("logJoin").arg("foo"); log.verify("ctor").arg("foo"); log.verify("ctor").arg("foo"); log.verify("ctor").arg("dummy") .before("ctor").arg(bar.getID()) .before("ctor").arg("foo"); log.kill(); foo.noteMsg("dummy killed"); log.verifyEvent("dtor").on("dummy") .beforeCall("noteMsg").on("foo"); // and when actually no exception is raised, this is an ASSERTION failure VERIFY_ERROR (ASSERTION, VERIFY_ERROR (EXCEPTION, dontThrow() )); #endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #975 } }; LAUNCHER (TestEventLog_test, "unit common"); }}} // namespace lib::test::test