diff options
-rw-r--r-- | src/core/Node.cpp | 48 | ||||
-rw-r--r-- | src/core/Node.hpp | 228 | ||||
-rw-r--r-- | src/core/managed/Managed.cpp | 16 | ||||
-rw-r--r-- | src/core/managed/Managed.hpp | 34 | ||||
-rw-r--r-- | src/core/managed/Manager.cpp | 64 | ||||
-rw-r--r-- | src/core/managed/Manager.hpp | 50 | ||||
-rw-r--r-- | test/core/NodeTest.cpp | 196 | ||||
-rw-r--r-- | test/core/managed/ManagedTest.cpp | 94 |
8 files changed, 259 insertions, 471 deletions
diff --git a/src/core/Node.cpp b/src/core/Node.cpp index 665430c..fa6a3a2 100644 --- a/src/core/Node.cpp +++ b/src/core/Node.cpp @@ -25,8 +25,10 @@ namespace ousia { void Node::setName(std::string name) { // Call the name change event - NameChangeEvent ev{this->name, name}; - triggerEvent(ev); + { + NameChangeEvent ev{this->name, name}; + triggerEvent(ev); + } // Set the new name this->name = std::move(name); @@ -97,48 +99,6 @@ std::vector<Rooted<Managed>> Node::resolve(const std::vector<std::string> &path, return res; } -int Node::registerEventHandler(EventType type, EventHandler handler, - Handle<Managed> owner, - bool includeChildren) -{ - const int id = handlerIdCounter++; - handlers.insert(std::make_pair( - type, - EventHandlerDescriptor{id, handler, owner, this, includeChildren})); - return id; -} - -bool Node::unregisterEventHandler(int id) { - for (auto it = handlers.begin(); it != handlers.end(); it++) { - if (it->second.id == id) { - handlers.erase(it); - return true; - } - } - return false; -} - -bool Node::triggerEvent(Event &event, bool fromChild) { - bool res = false; - // Iterate over all event handlers - const auto range = handlers.equal_range(event.type); - for (auto it = range.first; it != range.second; it++) { - // Fetch a reference to the descriptor, check whether it should be - // called for bubbled events - EventHandlerDescriptor descr = it->second; - if (!fromChild || descr.includeChildren) { - descr.handler(event, descr.owner); - res = true; - } - } - - // If possible, let the event bubble up to the parent node - if (event.canBubble() && !parent.isNull()) { - res = parent->triggerEvent(event, true) | res; - } - return res; -} - /* RTTI type registrations */ const Rtti<Node> RttiTypes::Node{"Node"}; diff --git a/src/core/Node.hpp b/src/core/Node.hpp index 50f9a96..cca33f7 100644 --- a/src/core/Node.hpp +++ b/src/core/Node.hpp @@ -31,189 +31,6 @@ namespace ousia { -/* Forward declarations */ -class Node; -class Event; - -/** - * EventType is an enum containing all possible node events. New event types - * should be added here. - */ -enum class EventType : int { - /** - * Generic update event which may be triggered if some important property - * of the node is changed. - */ - UPDATE, - - /** - * The NAME_CHANGE event is used to inform listeners that the name of the - * node has changed. - */ - NAME_CHANGE, - - /** - * The ADD_CHILD event is used to inform listeners that the node got a new - * child in any of its child node lists. - */ - ADD_CHILD, - - /** - * The DELETE_CHILD event is used to inform listeners that the node got a - * new child in any of its child node lists. - */ - DELETE_CHILD -}; - -/** - * Definition of the EventHandler function. - * - * @param event is a reference to the object holding the event data. - * @param owner is a reference to the managed object that was given in the - * registerEventHandler function. - */ -using EventHandler = void (*)(const Event &event, Handle<Managed> owner); - -/** - * The Event class and its child classes are responsible for containing the - * actual event data which further describes the event to the event handlers. - * Instances of this class and its children must be declared on the stack or as - * a temporary. - */ -class Event { -private: - /** - * True as long as the event can bubble up the node hirarchy. - */ - mutable bool bubble; - -public: - /** - * Contains the actual event type of this class. - */ - const EventType type; - - /** - * Node on which the event was triggered. - */ - Rooted<Node> sender; - - /** - * Constructor of the Event class. - * - * @param type is an element from the EventType enum. - * @param bubble if set to true, the event can bubble up the node hirarchy. - */ - Event(EventType type, bool bubble = true) : bubble(bubble), type(type){}; - - /** - * Delete the copy constructor. - */ - Event(const Event &) = delete; - - /** - * Delete the assignment operator. - */ - Event &operator=(const Event &) = delete; - - /** - * Stops the propagation of this event to the parent element. - */ - void stopPropagation() const { bubble = false; } - - /** - * Returns true if the event can still bubble. - */ - bool canBubble() const { return bubble; } -}; - -/** - * Event used when the name of a node has changed. - */ -class NameChangeEvent : public Event { -public: - /** - * Reference to a string containing the old name of the node. - */ - const std::string &oldName; - - /** - * Reference to a string containing the new name of the node. - */ - const std::string &newName; - - /** - * Constructor of the NameChangeEvent class. - * - * @param oldName is a reference to a string containing the old name of the - * node. - * @param newName is a reference to a string containing the new name of the - * node. - * @param bubble if set to true, the event can bubble up the node hirarchy. - */ - NameChangeEvent(const std::string &oldName, const std::string &newName, - bool bubble = true) - : Event(EventType::NAME_CHANGE, bubble), - oldName(oldName), - newName(newName) - { - } -}; - -/** - * Struct containing the data which describes a single registered event handler. - * Note that the event type (e.g. which type of event this element was - * registered for) is stored outside the EventHandlerDescriptor (in the map - * storing the registered event handlers). - */ -struct EventHandlerDescriptor { - /** - * Unique id of the event handler. - */ - const int id; - - /** - * Reference to the event handler containing the events. - */ - const EventHandler handler; - - /** - * Reference to the managed element which owns the event handler. The object - * which owns the Owned handler is given in the constructor. - */ - const Owned<Managed> owner; - - /** - * Set to true, if this event handler listens to bubbled events comming from - * child nodes. - */ - const bool includeChildren; - - /** - * Constructor of the EventHandlerDescriptor struct. - * - * @param id is the node-unique id of the EventHandlerDescriptor. - * @param handler is the function pointer which is going to be called once - * the associated event handler has fired. - * @param owner is a user-specified object which owns the method that is - * going to be called. This can be used to make sure that the method which - * handles the events has access to its owned object as long as the event - * handler lives. - * @param parent is the parent element this descriptor belongs to. The - * a handle to the "owner" object will be created on behalf of the parent. - * @param includeChildren is set to true if the event handler should handle - * events comming from child elements. - */ - EventHandlerDescriptor(int id, EventHandler handler, Handle<Managed> owner, - Managed *parent, bool includeChildren) - : id(id), - handler(handler), - owner(owner, parent), - includeChildren(includeChildren) - { - } -}; - /** * The Node class builds the base class for any Node within the DOM graph. A * node may either be a descriptive node (such as a domain description etc.) @@ -270,17 +87,6 @@ private: Owned<Node> parent; /** - * Current id counter. The id counter may be used to create ids which are - * unique inside the realm of this manager instance. - */ - int handlerIdCounter = 0; - - /** - * Multimap containing all registered event handlers for this node. - */ - std::multimap<EventType, EventHandlerDescriptor> handlers; - - /** * Private version of the "path" function used to construct the path. Calls * the path function of the parent node and adds the own name to the given * vector. @@ -482,40 +288,6 @@ public: { return resolve(std::vector<std::string>{name}, nullptr, nullptr); } - - /** - * Registers a new event handler for listening to the given event type. - * - * @param type is the event type the handler should listen to. - * @param handler is the handler that should be called. - * @param owner is an object the handler belongs to. May be nullptr. - * @param includeChildren if set to true, the event handler is also called - * if the same event is triggered on one of the child nodes. - * @return a unique event handler. - */ - int registerEventHandler(EventType type, EventHandler handler, - Handle<Managed> owner = nullptr, - bool includeChildren = false); - - /** - * Unregisters the given event handler from the node. Note that removing an - * event handler has linear time. - * - * @param id is the unique event handler id. - * @return true if the given event handler was successfully unregistered. - */ - bool unregisterEventHandler(int id); - - /** - * Triggers an event on this node. - * - * @param event is a pointer at the event that should be triggered. The - * calling function has ownership over the given event. - * @param fromChild is set to true if the triggerEvent function is called - * from a child node. - * @return true if any event handler was found. - */ - bool triggerEvent(Event &event, bool fromChild = false); }; // TODO: Use a different listener here for updating name maps diff --git a/src/core/managed/Managed.cpp b/src/core/managed/Managed.cpp index dc3731f..d9db0e0 100644 --- a/src/core/managed/Managed.cpp +++ b/src/core/managed/Managed.cpp @@ -54,6 +54,22 @@ bool Managed::deleteData(const std::string &key) { return mgr.deleteData(this, key); } +EventId Managed::registerEvent(EventType type, EventHandler handler, + Handle<Managed> owner) +{ + return mgr.registerEvent(this, type, handler, owner.get()); +} + +bool Managed::unregisterEvent(EventId id) +{ + return mgr.unregisterEvent(this, id); +} + +bool Managed::triggerEvent(Event &data) +{ + return mgr.triggerEvent(this, data); +} + const RttiBase &Managed::type() const { return typeOf(*this); diff --git a/src/core/managed/Managed.hpp b/src/core/managed/Managed.hpp index 5daa667..4a38dbd 100644 --- a/src/core/managed/Managed.hpp +++ b/src/core/managed/Managed.hpp @@ -135,6 +135,40 @@ public: bool deleteData(const std::string &key); + /* Event handling methods */ + + /** + * Registers an event handler for an event of the given type. + * + * @param type is the event type that should be registered. + * @param handler is the callback function. + * @param owner is a managed object that owns the event handler. A reference + * from the the reference object to the owner is added. The argument may be + * nullptr in which case no reference is added. The owner is passed to the + * event handler as second parameter. + * @return a numeric event id, which is unique for the given reference + * object. The event id must be used when unregistering event handlers. + */ + EventId registerEvent(EventType type, EventHandler handler, + Handle<Managed> owner); + + /** + * Unregisters the event with the given event id. + * + * @param id is the event that should be unregistered as returned by the + * registerEvent function. + * @return true if the operation was successful, false if either the + * reference object or the event id do not exist. + */ + bool unregisterEvent(EventId id); + + /** + * Triggers the event of the given type for the reference object. + * + * @param data is the event data that should be passed to the handlers. + */ + bool triggerEvent(Event &data); + /* RTTI methods */ /** diff --git a/src/core/managed/Manager.cpp b/src/core/managed/Manager.cpp index fbf1bd3..94eb1b1 100644 --- a/src/core/managed/Manager.cpp +++ b/src/core/managed/Manager.cpp @@ -256,8 +256,9 @@ void Manager::deleteObject(Managed *o, ObjectDescriptor *descr) deleteRef(descr->refOut.begin()->first, o, true); } - // Remove the data store entry + // Remove the data store and the event store entry store.erase(o); + events.erase(o); // Remove the Managed from the "marked" set marked.erase(o); @@ -442,5 +443,66 @@ bool Manager::deleteData(Managed *ref, const std::string &key) } return false; } + +/* Class Manager: Event handling */ + +EventId Manager::registerEvent(Managed *ref, EventType type, + EventHandler handler, Managed *owner) +{ + // Add a reference from the reference object to the owner object + if (owner) { + addRef(owner, ref); + } + + // Create a event handler descriptor and store it along with the + auto &vec = events.emplace(ref, std::vector<EventHandlerDescriptor>{}) + .first->second; + const EventHandlerDescriptor descr(type, handler, owner); + for (size_t i = 0; i < vec.size(); i++) { + if (!vec[i].handler) { + vec[i] = descr; + return i; + } + } + vec.push_back(descr); + return vec.size() - 1; +} + +bool Manager::unregisterEvent(Managed *ref, EventId id) +{ + auto eventsIt = events.find(ref); + if (eventsIt != events.end()) { + auto &vec = eventsIt->second; + if (id < vec.size() && vec[id].handler) { + // Delete the reference from the reference object to the handler + EventHandlerDescriptor &descr = vec[id]; + if (descr.owner) { + deleteRef(descr.owner, ref); + } + + // Remove the handler from the list by resetting handler and owner + // to nullptr + descr.handler = nullptr; + descr.owner = nullptr; + return true; + } + } + return false; +} + +bool Manager::triggerEvent(Managed *ref, Event &data) +{ + bool hasHandler = false; + auto eventsIt = events.find(ref); + if (eventsIt != events.end()) { + for (EventHandlerDescriptor &descr : eventsIt->second) { + if (descr.type == data.type && descr.handler) { + descr.handler(data, descr.owner); + hasHandler = true; + } + } + } + return hasHandler; +} } diff --git a/src/core/managed/Manager.hpp b/src/core/managed/Manager.hpp index 303e591..0e9d519 100644 --- a/src/core/managed/Manager.hpp +++ b/src/core/managed/Manager.hpp @@ -35,6 +35,8 @@ #include <vector> #include <queue> +#include "Events.hpp" + namespace ousia { // Forward declaration @@ -166,9 +168,9 @@ private: std::unordered_map<Managed *, std::map<std::string, Managed *>> store; /** - * Map for storing the tagged memory regions. + * Map storing any attached events. */ - std::map<uintptr_t, std::pair<uintptr_t, void *>> tags; + std::unordered_map<Managed *, std::vector<EventHandlerDescriptor>> events; /** * Recursion depth while performing deletion. This variable is needed @@ -225,6 +227,8 @@ public: */ ~Manager(); + /* Reference management and garbage collection */ + /** * Registers an object for being managed by the Manager. The Manager now has * the sole responsibility for freeing the managed object. Under no @@ -266,6 +270,8 @@ public: */ void sweep(); + /* Data storage */ + /** * Registers some arbitrary data (in form of a Managed object) for the * given reference Managed object under a certain (string) key. Overrides @@ -304,6 +310,46 @@ public: * @return true if data for this key was deleted, false otherwise. */ bool deleteData(Managed *ref, const std::string &key); + + /* Events */ + + /** + * Registers an event handler for an event of the given type for the object + * referenced by ref. + * + * @param ref is the reference object for which the event should be + * registered. + * @param type is the event type that should be registered. + * @param handler is the callback function. + * @param owner is a managed object that owns the event handler. A reference + * from the the reference object to the owner is added. The argument may be + * nullptr in which case no reference is added. The owner is passed to the + * event handler as second parameter. + * @return a numeric event id, which is unique for the given reference + * object. The event id must be used when unregistering event handlers. + */ + EventId registerEvent(Managed *ref, EventType type, EventHandler handler, + Managed *owner); + + /** + * Unregisters the event with the given event id from the given reference + * object. + * + * @param ref is the reference object from which the event should be + * removed. + * @param id is the event that should be unregistered. + * @return true if the operation was successful, false if either the + * reference object or the event id do not exist. + */ + bool unregisterEvent(Managed *ref, EventId id); + + /** + * Triggers the event of the given type for the reference object. + * + * @param ref is the object for which the given event should be triggered. + * @param data is the event data that should be passed to the handlers. + */ + bool triggerEvent(Managed *ref, Event &data); }; } diff --git a/test/core/NodeTest.cpp b/test/core/NodeTest.cpp index 334fcc8..d0cf08e 100644 --- a/test/core/NodeTest.cpp +++ b/test/core/NodeTest.cpp @@ -87,201 +87,5 @@ TEST(Node, simpleResolve) ASSERT_TRUE(child11 == *(res.begin())); } -class TestManagedEventOwner : public Managed { -public: - using Managed::Managed; - - int triggered = false; -}; - -static void handleEvent(const Event &ev, Handle<Managed> owner) -{ - owner.cast<TestManagedEventOwner>()->triggered++; -} - -static void handleEventStop(const Event &ev, Handle<Managed> owner) -{ - owner.cast<TestManagedEventOwner>()->triggered++; - ev.stopPropagation(); -} - -TEST(Node, events) -{ - Manager mgr; - Rooted<Node> n{new Node(mgr)}; - - Rooted<TestManagedEventOwner> e1{new TestManagedEventOwner(mgr)}; - Rooted<TestManagedEventOwner> e2{new TestManagedEventOwner(mgr)}; - Rooted<TestManagedEventOwner> e3{new TestManagedEventOwner(mgr)}; - - ASSERT_EQ(0, n->registerEventHandler(EventType::UPDATE, handleEvent, e1)); - ASSERT_EQ(1, n->registerEventHandler(EventType::NAME_CHANGE, handleEvent, e2)); - ASSERT_EQ(2, n->registerEventHandler(EventType::NAME_CHANGE, handleEvent, e3)); - - ASSERT_FALSE(e1->triggered); - ASSERT_FALSE(e2->triggered); - ASSERT_FALSE(e3->triggered); - - { - Event ev{EventType::ADD_CHILD}; - ASSERT_FALSE(n->triggerEvent(ev)); - } - - { - Event ev{EventType::UPDATE}; - ASSERT_TRUE(n->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(0, e2->triggered); - ASSERT_EQ(0, e3->triggered); - } - - { - Event ev{EventType::NAME_CHANGE}; - ASSERT_TRUE(n->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(1, e2->triggered); - ASSERT_EQ(1, e3->triggered); - } - - ASSERT_TRUE(n->unregisterEventHandler(1)); - ASSERT_FALSE(n->unregisterEventHandler(1)); - - { - Event ev{EventType::NAME_CHANGE}; - ASSERT_TRUE(n->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(1, e2->triggered); - ASSERT_EQ(2, e3->triggered); - } - - ASSERT_TRUE(n->unregisterEventHandler(0)); - ASSERT_FALSE(n->unregisterEventHandler(0)); - - { - Event ev{EventType::UPDATE}; - ASSERT_FALSE(n->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(1, e2->triggered); - ASSERT_EQ(2, e3->triggered); - } - - ASSERT_TRUE(n->unregisterEventHandler(2)); - ASSERT_FALSE(n->unregisterEventHandler(2)); - - { - Event ev{EventType::NAME_CHANGE}; - ASSERT_FALSE(n->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(1, e2->triggered); - ASSERT_EQ(2, e3->triggered); - } -} - -TEST(Node, eventBubbling) -{ - Manager mgr; - Rooted<Node> n1{new Node(mgr)}; - Rooted<Node> n2{new Node(mgr, n1)}; - - Rooted<TestManagedEventOwner> e1{new TestManagedEventOwner(mgr)}; - Rooted<TestManagedEventOwner> e2{new TestManagedEventOwner(mgr)}; - Rooted<TestManagedEventOwner> e3{new TestManagedEventOwner(mgr)}; - - ASSERT_EQ(0, n1->registerEventHandler(EventType::UPDATE, handleEvent, e1, true)); - ASSERT_EQ(1, n1->registerEventHandler(EventType::NAME_CHANGE, handleEvent, e2, true)); - ASSERT_EQ(2, n1->registerEventHandler(EventType::NAME_CHANGE, handleEvent, e3, false)); - - ASSERT_FALSE(e1->triggered); - ASSERT_FALSE(e2->triggered); - ASSERT_FALSE(e3->triggered); - - { - Event ev{EventType::ADD_CHILD}; - ASSERT_FALSE(n2->triggerEvent(ev)); - } - - { - Event ev{EventType::UPDATE}; - ASSERT_TRUE(n2->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(0, e2->triggered); - ASSERT_EQ(0, e3->triggered); - } - - { - Event ev{EventType::UPDATE, false}; - ASSERT_FALSE(n2->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(0, e2->triggered); - ASSERT_EQ(0, e3->triggered); - } - - { - Event ev{EventType::NAME_CHANGE}; - ASSERT_TRUE(n2->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(1, e2->triggered); - ASSERT_EQ(0, e3->triggered); - } - - ASSERT_TRUE(n1->unregisterEventHandler(1)); - ASSERT_FALSE(n1->unregisterEventHandler(1)); - - { - Event ev{EventType::NAME_CHANGE}; - ASSERT_FALSE(n2->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(1, e2->triggered); - ASSERT_EQ(0, e3->triggered); - } - - ASSERT_TRUE(n1->unregisterEventHandler(0)); - ASSERT_FALSE(n1->unregisterEventHandler(0)); - - { - Event ev{EventType::UPDATE}; - ASSERT_FALSE(n2->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(1, e2->triggered); - ASSERT_EQ(0, e3->triggered); - } - - ASSERT_TRUE(n1->unregisterEventHandler(2)); - ASSERT_FALSE(n1->unregisterEventHandler(2)); - - { - Event ev{EventType::NAME_CHANGE}; - ASSERT_FALSE(n2->triggerEvent(ev)); - ASSERT_EQ(1, e1->triggered); - ASSERT_EQ(1, e2->triggered); - ASSERT_EQ(0, e3->triggered); - } -} - -TEST(Node, eventStopPropagation) -{ - Manager mgr; - Rooted<Node> n1{new Node(mgr)}; - Rooted<Node> n2{new Node(mgr, n1)}; - - Rooted<TestManagedEventOwner> e1{new TestManagedEventOwner(mgr)}; - Rooted<TestManagedEventOwner> e2{new TestManagedEventOwner(mgr)}; - - ASSERT_EQ(0, n1->registerEventHandler(EventType::UPDATE, handleEvent, e1, true)); - ASSERT_EQ(0, n2->registerEventHandler(EventType::UPDATE, handleEventStop, e2, true)); - - ASSERT_FALSE(e1->triggered); - ASSERT_FALSE(e2->triggered); - - { - Event ev{EventType::UPDATE}; - n2->triggerEvent(ev); - - ASSERT_EQ(0, e1->triggered); - ASSERT_EQ(1, e2->triggered); - } - -} - } } diff --git a/test/core/managed/ManagedTest.cpp b/test/core/managed/ManagedTest.cpp index d6a392a..42ce076 100644 --- a/test/core/managed/ManagedTest.cpp +++ b/test/core/managed/ManagedTest.cpp @@ -100,5 +100,99 @@ TEST(Managed, type) ASSERT_EQ(&Type1, &typeOf<TypeTestManaged1>()); ASSERT_EQ(&Type1, &typeOf(*m1)); } + +class TestManagedEventOwner : public TestManaged { +public: + using TestManaged::TestManaged; + + int triggered = false; +}; + +static void handleEvent(const Event &ev, Managed *owner) +{ + static_cast<TestManagedEventOwner *>(owner)->triggered++; +} + +TEST(Managed, events) +{ + Manager mgr(1); + std::array<bool, 4> a; + { + Rooted<TestManaged> n{new TestManaged(mgr, a[0])}; + + Handle<TestManagedEventOwner> e1{new TestManagedEventOwner(mgr, a[1])}; + Handle<TestManagedEventOwner> e2{new TestManagedEventOwner(mgr, a[2])}; + Handle<TestManagedEventOwner> e3{new TestManagedEventOwner(mgr, a[3])}; + { + Rooted<TestManagedEventOwner> re1{e1}; + Rooted<TestManagedEventOwner> re2{e2}; + Rooted<TestManagedEventOwner> re3{e3}; + + ASSERT_EQ(0, n->registerEvent(EventType::UPDATE, handleEvent, re1)); + ASSERT_EQ( + 1, n->registerEvent(EventType::NAME_CHANGE, handleEvent, re2)); + ASSERT_EQ( + 2, n->registerEvent(EventType::NAME_CHANGE, handleEvent, re3)); + ASSERT_TRUE(a[0] && a[1] && a[2] && a[3]); + } + ASSERT_TRUE(a[0] && a[1] && a[2] && a[3]); + + ASSERT_EQ(0, e1->triggered); + ASSERT_EQ(0, e2->triggered); + ASSERT_EQ(0, e3->triggered); + + { + Event ev{EventType::ADD_CHILD}; + ASSERT_FALSE(n->triggerEvent(ev)); + } + + { + Event ev{EventType::UPDATE}; + ASSERT_TRUE(n->triggerEvent(ev)); + ASSERT_EQ(1, e1->triggered); + ASSERT_EQ(0, e2->triggered); + ASSERT_EQ(0, e3->triggered); + } + + { + Event ev{EventType::NAME_CHANGE}; + ASSERT_TRUE(n->triggerEvent(ev)); + ASSERT_EQ(1, e1->triggered); + ASSERT_EQ(1, e2->triggered); + ASSERT_EQ(1, e3->triggered); + } + + ASSERT_TRUE(n->unregisterEvent(1)); + ASSERT_FALSE(n->unregisterEvent(1)); + ASSERT_FALSE(a[2]); + + { + Event ev{EventType::NAME_CHANGE}; + ASSERT_TRUE(n->triggerEvent(ev)); + ASSERT_EQ(1, e1->triggered); + ASSERT_EQ(2, e3->triggered); + } + + ASSERT_TRUE(n->unregisterEvent(0)); + ASSERT_FALSE(n->unregisterEvent(0)); + ASSERT_FALSE(a[1]); + + { + Event ev{EventType::UPDATE}; + ASSERT_FALSE(n->triggerEvent(ev)); + ASSERT_EQ(2, e3->triggered); + } + + ASSERT_TRUE(n->unregisterEvent(2)); + ASSERT_FALSE(n->unregisterEvent(2)); + ASSERT_FALSE(a[3]); + + { + Event ev{EventType::NAME_CHANGE}; + ASSERT_FALSE(n->triggerEvent(ev)); + } + } + ASSERT_FALSE(a[0] || a[1] || a[2] || a[3]); +} } |