#include "common.hh" #include "observer_list.hh" #include #include namespace { class Observer { public: virtual ~Observer() = default; virtual void foo() = 0; }; class MockObserver : public Observer { public: MOCK_METHOD(void, foo, (), (override)); }; } // namespace TEST(observer_list, empty) { ObserverList observers; EXPECT_TRUE(observers.empty()); auto it = observers.notify(); EXPECT_FALSE(it); ++it; EXPECT_FALSE(it); } TEST(observer_list, sanity) { ObserverList observers; MockObserver observer; observers.add(&observer); EXPECT_CALL(observer, foo()); for (auto it = observers.notify(); it; ++it) it->foo(); } TEST(observer_list, observer_removing_next_observer) { ObserverList observers; MockObserver observer1; MockObserver observer2; observers.add(&observer1); observers.add(&observer2); EXPECT_CALL(observer1, foo()) .WillOnce([&]() { observers.remove(&observer2); }) .WillOnce(testing::Return()); EXPECT_CALL(observer2, foo()) .Times(0); for (auto it = observers.notify(); it; ++it) it->foo(); for (auto it = observers.notify(); it; ++it) it->foo(); } TEST(observer_list, observer_removing_previous_observer) { ObserverList observers; MockObserver observer1; MockObserver observer2; observers.add(&observer1); observers.add(&observer2); EXPECT_CALL(observer1, foo()); EXPECT_CALL(observer2, foo()) .WillOnce([&]() { observers.remove(&observer1); }) .WillOnce(testing::Return()); for (auto it = observers.notify(); it; ++it) it->foo(); for (auto it = observers.notify(); it; ++it) it->foo(); } TEST(observer_list, observer_removing_itself) { ObserverList observers; MockObserver observer; observers.add(&observer); EXPECT_CALL(observer, foo()) .WillOnce([&]() { observers.remove(&observer); }); for (auto it = observers.notify(); it; ++it) it->foo(); EXPECT_TRUE(observers.empty()); } TEST(observer_list, observer_adding_observer) { ObserverList observers; MockObserver observer1; MockObserver observer2; observers.add(&observer1); EXPECT_CALL(observer1, foo()) .WillOnce([&]() { observers.add(&observer2); }) .WillOnce(testing::Return()); EXPECT_CALL(observer2, foo()); for (auto it = observers.notify(); it; ++it) it->foo(); for (auto it = observers.notify(); it; ++it) it->foo(); } TEST(observer_list, observer_start_new_notify) { ObserverList observers; MockObserver observer1; MockObserver observer2; observers.add(&observer1); observers.add(&observer2); EXPECT_CALL(observer1, foo()) .WillOnce([&]() { observers.remove(&observer1); for (auto it = observers.notify(); it; ++it) it->foo(); }); EXPECT_CALL(observer2, foo()) .Times(2); for (auto it = observers.notify(); it; ++it) it->foo(); }