| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/events/platform/platform_event_source.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/macros.h" |
| #include "base/memory/scoped_vector.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "base/single_thread_task_runner.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/events/platform/platform_event_dispatcher.h" |
| #include "ui/events/platform/platform_event_observer.h" |
| #include "ui/events/platform/scoped_event_dispatcher.h" |
| |
| namespace ui { |
| |
| namespace { |
| |
| std::unique_ptr<PlatformEvent> CreatePlatformEvent() { |
| std::unique_ptr<PlatformEvent> event(new PlatformEvent()); |
| memset(event.get(), 0, sizeof(PlatformEvent)); |
| return event; |
| } |
| |
| template <typename T> |
| void DestroyScopedPtr(std::unique_ptr<T> object) {} |
| |
| void RemoveDispatcher(PlatformEventDispatcher* dispatcher) { |
| PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(dispatcher); |
| } |
| |
| void RemoveDispatchers(PlatformEventDispatcher* first, |
| PlatformEventDispatcher* second) { |
| PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(first); |
| PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(second); |
| } |
| |
| void AddDispatcher(PlatformEventDispatcher* dispatcher) { |
| PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(dispatcher); |
| } |
| |
| } // namespace |
| |
| class TestPlatformEventSource : public PlatformEventSource { |
| public: |
| TestPlatformEventSource() |
| : stop_stream_(false) { |
| } |
| ~TestPlatformEventSource() override {} |
| |
| uint32_t Dispatch(const PlatformEvent& event) { return DispatchEvent(event); } |
| |
| // Dispatches the stream of events, and returns the number of events that are |
| // dispatched before it is requested to stop. |
| size_t DispatchEventStream(const ScopedVector<PlatformEvent>& events) { |
| stop_stream_ = false; |
| for (size_t count = 0; count < events.size(); ++count) { |
| DispatchEvent(*events[count]); |
| if (stop_stream_) |
| return count + 1; |
| } |
| return events.size(); |
| } |
| |
| // PlatformEventSource: |
| void StopCurrentEventStream() override { stop_stream_ = true; } |
| |
| private: |
| bool stop_stream_; |
| DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource); |
| }; |
| |
| class TestPlatformEventDispatcher : public PlatformEventDispatcher { |
| public: |
| TestPlatformEventDispatcher(int id, std::vector<int>* list) |
| : id_(id), |
| list_(list), |
| post_dispatch_action_(POST_DISPATCH_NONE) { |
| PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); |
| } |
| ~TestPlatformEventDispatcher() override { |
| PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); |
| } |
| |
| void set_post_dispatch_action(uint32_t action) { |
| post_dispatch_action_ = action; |
| } |
| |
| protected: |
| // PlatformEventDispatcher: |
| bool CanDispatchEvent(const PlatformEvent& event) override { return true; } |
| |
| uint32_t DispatchEvent(const PlatformEvent& event) override { |
| list_->push_back(id_); |
| return post_dispatch_action_; |
| } |
| |
| private: |
| int id_; |
| std::vector<int>* list_; |
| uint32_t post_dispatch_action_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestPlatformEventDispatcher); |
| }; |
| |
| class TestPlatformEventObserver : public PlatformEventObserver { |
| public: |
| TestPlatformEventObserver(int id, std::vector<int>* list) |
| : id_(id), list_(list) { |
| PlatformEventSource::GetInstance()->AddPlatformEventObserver(this); |
| } |
| ~TestPlatformEventObserver() override { |
| PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this); |
| } |
| |
| protected: |
| // PlatformEventObserver: |
| void WillProcessEvent(const PlatformEvent& event) override { |
| list_->push_back(id_); |
| } |
| |
| void DidProcessEvent(const PlatformEvent& event) override {} |
| |
| private: |
| int id_; |
| std::vector<int>* list_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestPlatformEventObserver); |
| }; |
| |
| class PlatformEventTest : public testing::Test { |
| public: |
| PlatformEventTest() {} |
| ~PlatformEventTest() override {} |
| |
| TestPlatformEventSource* source() { return source_.get(); } |
| |
| protected: |
| // testing::Test: |
| void SetUp() override { source_.reset(new TestPlatformEventSource()); } |
| |
| private: |
| std::unique_ptr<TestPlatformEventSource> source_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PlatformEventTest); |
| }; |
| |
| // Tests that a dispatcher receives an event. |
| TEST_F(PlatformEventTest, DispatcherBasic) { |
| std::vector<int> list_dispatcher; |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| EXPECT_EQ(0u, list_dispatcher.size()); |
| { |
| TestPlatformEventDispatcher dispatcher(1, &list_dispatcher); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(1u, list_dispatcher.size()); |
| EXPECT_EQ(1, list_dispatcher[0]); |
| } |
| |
| list_dispatcher.clear(); |
| event = CreatePlatformEvent(); |
| source()->Dispatch(*event); |
| EXPECT_EQ(0u, list_dispatcher.size()); |
| } |
| |
| // Tests that dispatchers receive events in the correct order. |
| TEST_F(PlatformEventTest, DispatcherOrder) { |
| std::vector<int> list_dispatcher; |
| int sequence[] = {21, 3, 6, 45}; |
| ScopedVector<TestPlatformEventDispatcher> dispatchers; |
| for (size_t i = 0; i < arraysize(sequence); ++i) { |
| dispatchers.push_back( |
| new TestPlatformEventDispatcher(sequence[i], &list_dispatcher)); |
| } |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(arraysize(sequence), list_dispatcher.size()); |
| EXPECT_EQ(std::vector<int>(sequence, sequence + arraysize(sequence)), |
| list_dispatcher); |
| } |
| |
| // Tests that if a dispatcher consumes the event, the subsequent dispatchers do |
| // not receive the event. |
| TEST_F(PlatformEventTest, DispatcherConsumesEventToStopDispatch) { |
| std::vector<int> list_dispatcher; |
| TestPlatformEventDispatcher first(12, &list_dispatcher); |
| TestPlatformEventDispatcher second(23, &list_dispatcher); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list_dispatcher.size()); |
| EXPECT_EQ(12, list_dispatcher[0]); |
| EXPECT_EQ(23, list_dispatcher[1]); |
| list_dispatcher.clear(); |
| |
| first.set_post_dispatch_action(POST_DISPATCH_STOP_PROPAGATION); |
| event = CreatePlatformEvent(); |
| source()->Dispatch(*event); |
| ASSERT_EQ(1u, list_dispatcher.size()); |
| EXPECT_EQ(12, list_dispatcher[0]); |
| } |
| |
| // Tests that observers receive events. |
| TEST_F(PlatformEventTest, ObserverBasic) { |
| std::vector<int> list_observer; |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| EXPECT_EQ(0u, list_observer.size()); |
| { |
| TestPlatformEventObserver observer(31, &list_observer); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(1u, list_observer.size()); |
| EXPECT_EQ(31, list_observer[0]); |
| } |
| |
| list_observer.clear(); |
| event = CreatePlatformEvent(); |
| source()->Dispatch(*event); |
| EXPECT_EQ(0u, list_observer.size()); |
| } |
| |
| // Tests that observers receive events in the correct order. |
| TEST_F(PlatformEventTest, ObserverOrder) { |
| std::vector<int> list_observer; |
| const int sequence[] = {21, 3, 6, 45}; |
| ScopedVector<TestPlatformEventObserver> observers; |
| for (size_t i = 0; i < arraysize(sequence); ++i) { |
| observers.push_back( |
| new TestPlatformEventObserver(sequence[i], &list_observer)); |
| } |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(arraysize(sequence), list_observer.size()); |
| EXPECT_EQ(std::vector<int>(sequence, sequence + arraysize(sequence)), |
| list_observer); |
| } |
| |
| // Tests that observers and dispatchers receive events in the correct order. |
| TEST_F(PlatformEventTest, DispatcherAndObserverOrder) { |
| std::vector<int> list; |
| TestPlatformEventDispatcher first_d(12, &list); |
| TestPlatformEventObserver first_o(10, &list); |
| TestPlatformEventDispatcher second_d(23, &list); |
| TestPlatformEventObserver second_o(20, &list); |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| const int expected[] = {10, 20, 12, 23}; |
| EXPECT_EQ(std::vector<int>(expected, expected + arraysize(expected)), list); |
| } |
| |
| // Tests that an overridden dispatcher receives events before the default |
| // dispatchers. |
| TEST_F(PlatformEventTest, OverriddenDispatcherBasic) { |
| std::vector<int> list; |
| TestPlatformEventDispatcher dispatcher(10, &list); |
| TestPlatformEventObserver observer(15, &list); |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(10, list[1]); |
| list.clear(); |
| |
| TestPlatformEventDispatcher overriding_dispatcher(20, &list); |
| source()->RemovePlatformEventDispatcher(&overriding_dispatcher); |
| std::unique_ptr<ScopedEventDispatcher> handle = |
| source()->OverrideDispatcher(&overriding_dispatcher); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(20, list[1]); |
| } |
| |
| // Tests that an overridden dispatcher can request that the default dispatchers |
| // can dispatch the events. |
| TEST_F(PlatformEventTest, OverriddenDispatcherInvokeDefaultDispatcher) { |
| std::vector<int> list; |
| TestPlatformEventDispatcher dispatcher(10, &list); |
| TestPlatformEventObserver observer(15, &list); |
| TestPlatformEventDispatcher overriding_dispatcher(20, &list); |
| source()->RemovePlatformEventDispatcher(&overriding_dispatcher); |
| std::unique_ptr<ScopedEventDispatcher> handle = |
| source()->OverrideDispatcher(&overriding_dispatcher); |
| overriding_dispatcher.set_post_dispatch_action(POST_DISPATCH_PERFORM_DEFAULT); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| // First the observer, then the overriding dispatcher, then the default |
| // dispatcher. |
| ASSERT_EQ(3u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(20, list[1]); |
| EXPECT_EQ(10, list[2]); |
| list.clear(); |
| |
| // Install a second overriding dispatcher. |
| TestPlatformEventDispatcher second_overriding(50, &list); |
| source()->RemovePlatformEventDispatcher(&second_overriding); |
| std::unique_ptr<ScopedEventDispatcher> second_override_handle = |
| source()->OverrideDispatcher(&second_overriding); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(50, list[1]); |
| list.clear(); |
| |
| second_overriding.set_post_dispatch_action(POST_DISPATCH_PERFORM_DEFAULT); |
| source()->Dispatch(*event); |
| // First the observer, then the second overriding dispatcher, then the default |
| // dispatcher. |
| ASSERT_EQ(3u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(50, list[1]); |
| EXPECT_EQ(10, list[2]); |
| } |
| |
| // Runs a callback during an event dispatch. |
| class RunCallbackDuringDispatch : public TestPlatformEventDispatcher { |
| public: |
| RunCallbackDuringDispatch(int id, std::vector<int>* list) |
| : TestPlatformEventDispatcher(id, list) {} |
| ~RunCallbackDuringDispatch() override {} |
| |
| void set_callback(const base::Closure& callback) { |
| callback_ = callback; |
| } |
| |
| protected: |
| // PlatformEventDispatcher: |
| uint32_t DispatchEvent(const PlatformEvent& event) override { |
| if (!callback_.is_null()) |
| callback_.Run(); |
| return TestPlatformEventDispatcher::DispatchEvent(event); |
| } |
| |
| private: |
| base::Closure callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RunCallbackDuringDispatch); |
| }; |
| |
| // Test that if a dispatcher removes another dispatcher that is later in the |
| // dispatcher list during dispatching an event, then event dispatching still |
| // continues correctly. |
| TEST_F(PlatformEventTest, DispatcherRemovesNextDispatcherDuringDispatch) { |
| std::vector<int> list; |
| TestPlatformEventDispatcher first(10, &list); |
| RunCallbackDuringDispatch second(15, &list); |
| TestPlatformEventDispatcher third(20, &list); |
| TestPlatformEventDispatcher fourth(30, &list); |
| |
| second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&third))); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| // |second| removes |third| from the dispatcher list during dispatch. So the |
| // event should only reach |first|, |second|, and |fourth|. |
| ASSERT_EQ(3u, list.size()); |
| EXPECT_EQ(10, list[0]); |
| EXPECT_EQ(15, list[1]); |
| EXPECT_EQ(30, list[2]); |
| } |
| |
| // Tests that if a dispatcher removes itself from the dispatcher list during |
| // dispatching an event, then event dispatching continues correctly. |
| TEST_F(PlatformEventTest, DispatcherRemovesSelfDuringDispatch) { |
| std::vector<int> list; |
| TestPlatformEventDispatcher first(10, &list); |
| RunCallbackDuringDispatch second(15, &list); |
| TestPlatformEventDispatcher third(20, &list); |
| |
| second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&second))); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| // |second| removes itself from the dispatcher list during dispatch. So the |
| // event should reach all three dispatchers in the list. |
| ASSERT_EQ(3u, list.size()); |
| EXPECT_EQ(10, list[0]); |
| EXPECT_EQ(15, list[1]); |
| EXPECT_EQ(20, list[2]); |
| } |
| |
| // Tests that if a dispatcher removes itself from the dispatcher list during |
| // dispatching an event, and this dispatcher is last in the dispatcher-list, |
| // then event dispatching ends correctly. |
| TEST_F(PlatformEventTest, DispatcherRemovesSelfDuringDispatchLast) { |
| std::vector<int> list; |
| TestPlatformEventDispatcher first(10, &list); |
| RunCallbackDuringDispatch second(15, &list); |
| |
| second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&second))); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| // |second| removes itself during dispatch. So both dispatchers will have |
| // received the event. |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(10, list[0]); |
| EXPECT_EQ(15, list[1]); |
| } |
| |
| // Tests that if a dispatcher removes a single dispatcher that comes before it |
| // in the dispatcher list, then dispatch continues correctly. |
| TEST_F(PlatformEventTest, DispatcherRemovesPrevDispatcherDuringDispatch) { |
| std::vector<int> list; |
| TestPlatformEventDispatcher first(10, &list); |
| RunCallbackDuringDispatch second(15, &list); |
| TestPlatformEventDispatcher third(20, &list); |
| |
| second.set_callback(base::Bind(&RemoveDispatcher, base::Unretained(&first))); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| // |second| removes |first| from the dispatcher list during dispatch. The |
| // event should reach all three dispatchers. |
| ASSERT_EQ(3u, list.size()); |
| EXPECT_EQ(10, list[0]); |
| EXPECT_EQ(15, list[1]); |
| EXPECT_EQ(20, list[2]); |
| } |
| |
| // Tests that if a dispatcher removes multiple dispatchers that comes before it |
| // in the dispatcher list, then dispatch continues correctly. |
| TEST_F(PlatformEventTest, DispatcherRemovesPrevDispatchersDuringDispatch) { |
| std::vector<int> list; |
| TestPlatformEventDispatcher first(10, &list); |
| TestPlatformEventDispatcher second(12, &list); |
| RunCallbackDuringDispatch third(15, &list); |
| TestPlatformEventDispatcher fourth(20, &list); |
| |
| third.set_callback(base::Bind(&RemoveDispatchers, |
| base::Unretained(&first), |
| base::Unretained(&second))); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| // |third| removes |first| and |second| from the dispatcher list during |
| // dispatch. The event should reach all three dispatchers. |
| ASSERT_EQ(4u, list.size()); |
| EXPECT_EQ(10, list[0]); |
| EXPECT_EQ(12, list[1]); |
| EXPECT_EQ(15, list[2]); |
| EXPECT_EQ(20, list[3]); |
| } |
| |
| // Tests that adding a dispatcher during dispatching an event receives that |
| // event. |
| TEST_F(PlatformEventTest, DispatcherAddedDuringDispatchReceivesEvent) { |
| std::vector<int> list; |
| TestPlatformEventDispatcher first(10, &list); |
| RunCallbackDuringDispatch second(15, &list); |
| TestPlatformEventDispatcher third(20, &list); |
| TestPlatformEventDispatcher fourth(30, &list); |
| RemoveDispatchers(&third, &fourth); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(10, list[0]); |
| EXPECT_EQ(15, list[1]); |
| |
| second.set_callback(base::Bind(&AddDispatcher, base::Unretained(&third))); |
| list.clear(); |
| source()->Dispatch(*event); |
| ASSERT_EQ(3u, list.size()); |
| EXPECT_EQ(10, list[0]); |
| EXPECT_EQ(15, list[1]); |
| EXPECT_EQ(20, list[2]); |
| |
| second.set_callback(base::Bind(&AddDispatcher, base::Unretained(&fourth))); |
| list.clear(); |
| source()->Dispatch(*event); |
| ASSERT_EQ(4u, list.size()); |
| EXPECT_EQ(10, list[0]); |
| EXPECT_EQ(15, list[1]); |
| EXPECT_EQ(20, list[2]); |
| EXPECT_EQ(30, list[3]); |
| } |
| |
| // Provides mechanism for running tests from inside an active message-loop. |
| class PlatformEventTestWithMessageLoop : public PlatformEventTest { |
| public: |
| PlatformEventTestWithMessageLoop() {} |
| ~PlatformEventTestWithMessageLoop() override {} |
| |
| void Run() { |
| message_loop_.task_runner()->PostTask( |
| FROM_HERE, base::Bind(&PlatformEventTestWithMessageLoop::RunTest, |
| base::Unretained(this))); |
| message_loop_.Run(); |
| } |
| |
| protected: |
| void RunTest() { |
| RunTestImpl(); |
| message_loop_.QuitWhenIdle(); |
| } |
| |
| virtual void RunTestImpl() = 0; |
| |
| private: |
| base::MessageLoopForUI message_loop_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PlatformEventTestWithMessageLoop); |
| }; |
| |
| #define RUN_TEST_IN_MESSAGE_LOOP(name) \ |
| TEST_F(name, Run) { Run(); } |
| |
| // Tests that a ScopedEventDispatcher restores the previous dispatcher when |
| // destroyed. |
| class ScopedDispatcherRestoresAfterDestroy |
| : public PlatformEventTestWithMessageLoop { |
| public: |
| // PlatformEventTestWithMessageLoop: |
| void RunTestImpl() override { |
| std::vector<int> list; |
| TestPlatformEventDispatcher dispatcher(10, &list); |
| TestPlatformEventObserver observer(15, &list); |
| |
| TestPlatformEventDispatcher first_overriding(20, &list); |
| source()->RemovePlatformEventDispatcher(&first_overriding); |
| std::unique_ptr<ScopedEventDispatcher> first_override_handle = |
| source()->OverrideDispatcher(&first_overriding); |
| |
| // Install a second overriding dispatcher. |
| TestPlatformEventDispatcher second_overriding(50, &list); |
| source()->RemovePlatformEventDispatcher(&second_overriding); |
| std::unique_ptr<ScopedEventDispatcher> second_override_handle = |
| source()->OverrideDispatcher(&second_overriding); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(50, list[1]); |
| list.clear(); |
| |
| second_override_handle.reset(); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(20, list[1]); |
| } |
| }; |
| |
| RUN_TEST_IN_MESSAGE_LOOP(ScopedDispatcherRestoresAfterDestroy) |
| |
| // This dispatcher destroys the handle to the ScopedEventDispatcher when |
| // dispatching an event. |
| class DestroyScopedHandleDispatcher : public TestPlatformEventDispatcher { |
| public: |
| DestroyScopedHandleDispatcher(int id, std::vector<int>* list) |
| : TestPlatformEventDispatcher(id, list) {} |
| ~DestroyScopedHandleDispatcher() override {} |
| |
| void SetScopedHandle(std::unique_ptr<ScopedEventDispatcher> handler) { |
| handler_ = std::move(handler); |
| } |
| |
| void set_callback(const base::Closure& callback) { |
| callback_ = callback; |
| } |
| |
| private: |
| // PlatformEventDispatcher: |
| bool CanDispatchEvent(const PlatformEvent& event) override { return true; } |
| |
| uint32_t DispatchEvent(const PlatformEvent& event) override { |
| handler_.reset(); |
| uint32_t action = TestPlatformEventDispatcher::DispatchEvent(event); |
| if (!callback_.is_null()) { |
| callback_.Run(); |
| callback_ = base::Closure(); |
| } |
| return action; |
| } |
| |
| std::unique_ptr<ScopedEventDispatcher> handler_; |
| base::Closure callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DestroyScopedHandleDispatcher); |
| }; |
| |
| // Tests that resetting an overridden dispatcher causes the nested message-loop |
| // iteration to stop and the rest of the events are dispatched in the next |
| // iteration. |
| class DestroyedNestedOverriddenDispatcherQuitsNestedLoopIteration |
| : public PlatformEventTestWithMessageLoop { |
| public: |
| void NestedTask(std::vector<int>* list, |
| TestPlatformEventDispatcher* dispatcher) { |
| ScopedVector<PlatformEvent> events; |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| events.push_back(std::move(event)); |
| event = CreatePlatformEvent(); |
| events.push_back(std::move(event)); |
| |
| // Attempt to dispatch a couple of events. Dispatching the first event will |
| // have terminated the ScopedEventDispatcher object, which will terminate |
| // the current iteration of the message-loop. |
| size_t count = source()->DispatchEventStream(events); |
| EXPECT_EQ(1u, count); |
| ASSERT_EQ(2u, list->size()); |
| EXPECT_EQ(15, (*list)[0]); |
| EXPECT_EQ(20, (*list)[1]); |
| list->clear(); |
| |
| ASSERT_LT(count, events.size()); |
| events.erase(events.begin(), events.begin() + count); |
| |
| count = source()->DispatchEventStream(events); |
| EXPECT_EQ(1u, count); |
| ASSERT_EQ(2u, list->size()); |
| EXPECT_EQ(15, (*list)[0]); |
| EXPECT_EQ(10, (*list)[1]); |
| list->clear(); |
| |
| // Terminate the message-loop. |
| base::MessageLoopForUI::current()->QuitNow(); |
| } |
| |
| // PlatformEventTestWithMessageLoop: |
| void RunTestImpl() override { |
| std::vector<int> list; |
| TestPlatformEventDispatcher dispatcher(10, &list); |
| TestPlatformEventObserver observer(15, &list); |
| |
| DestroyScopedHandleDispatcher overriding(20, &list); |
| source()->RemovePlatformEventDispatcher(&overriding); |
| std::unique_ptr<ScopedEventDispatcher> override_handle = |
| source()->OverrideDispatcher(&overriding); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(20, list[1]); |
| list.clear(); |
| |
| overriding.SetScopedHandle(std::move(override_handle)); |
| base::RunLoop run_loop; |
| base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); |
| base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop); |
| loop->task_runner()->PostTask( |
| FROM_HERE, |
| base::Bind( |
| &DestroyedNestedOverriddenDispatcherQuitsNestedLoopIteration:: |
| NestedTask, |
| base::Unretained(this), base::Unretained(&list), |
| base::Unretained(&overriding))); |
| run_loop.Run(); |
| |
| // Dispatching the event should now reach the default dispatcher. |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(10, list[1]); |
| } |
| }; |
| |
| RUN_TEST_IN_MESSAGE_LOOP( |
| DestroyedNestedOverriddenDispatcherQuitsNestedLoopIteration) |
| |
| // Tests that resetting an overridden dispatcher, and installing another |
| // overridden dispatcher before the nested message-loop completely unwinds |
| // function correctly. |
| class ConsecutiveOverriddenDispatcherInTheSameMessageLoopIteration |
| : public PlatformEventTestWithMessageLoop { |
| public: |
| void NestedTask(std::unique_ptr<ScopedEventDispatcher> dispatch_handle, |
| std::vector<int>* list) { |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list->size()); |
| EXPECT_EQ(15, (*list)[0]); |
| EXPECT_EQ(20, (*list)[1]); |
| list->clear(); |
| |
| // Reset the override dispatcher. This should restore the default |
| // dispatcher. |
| dispatch_handle.reset(); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list->size()); |
| EXPECT_EQ(15, (*list)[0]); |
| EXPECT_EQ(10, (*list)[1]); |
| list->clear(); |
| |
| // Install another override-dispatcher. |
| DestroyScopedHandleDispatcher second_overriding(70, list); |
| source()->RemovePlatformEventDispatcher(&second_overriding); |
| std::unique_ptr<ScopedEventDispatcher> second_override_handle = |
| source()->OverrideDispatcher(&second_overriding); |
| |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list->size()); |
| EXPECT_EQ(15, (*list)[0]); |
| EXPECT_EQ(70, (*list)[1]); |
| list->clear(); |
| |
| second_overriding.SetScopedHandle(std::move(second_override_handle)); |
| second_overriding.set_post_dispatch_action(POST_DISPATCH_NONE); |
| base::RunLoop run_loop; |
| second_overriding.set_callback(run_loop.QuitClosure()); |
| base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); |
| base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop); |
| loop->task_runner()->PostTask( |
| FROM_HERE, |
| base::Bind(base::IgnoreResult(&TestPlatformEventSource::Dispatch), |
| base::Unretained(source()), *event)); |
| run_loop.Run(); |
| ASSERT_EQ(2u, list->size()); |
| EXPECT_EQ(15, (*list)[0]); |
| EXPECT_EQ(70, (*list)[1]); |
| list->clear(); |
| |
| // Terminate the message-loop. |
| base::MessageLoopForUI::current()->QuitNow(); |
| } |
| |
| // PlatformEventTestWithMessageLoop: |
| void RunTestImpl() override { |
| std::vector<int> list; |
| TestPlatformEventDispatcher dispatcher(10, &list); |
| TestPlatformEventObserver observer(15, &list); |
| |
| TestPlatformEventDispatcher overriding(20, &list); |
| source()->RemovePlatformEventDispatcher(&overriding); |
| std::unique_ptr<ScopedEventDispatcher> override_handle = |
| source()->OverrideDispatcher(&overriding); |
| |
| std::unique_ptr<PlatformEvent> event(CreatePlatformEvent()); |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(20, list[1]); |
| list.clear(); |
| |
| // Start a nested message-loop, and destroy |override_handle| in the nested |
| // loop. That should terminate the nested loop, restore the previous |
| // dispatchers, and return control to this function. |
| base::RunLoop run_loop; |
| base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); |
| base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop); |
| loop->task_runner()->PostTask( |
| FROM_HERE, |
| base::Bind( |
| &ConsecutiveOverriddenDispatcherInTheSameMessageLoopIteration:: |
| NestedTask, |
| base::Unretained(this), base::Passed(&override_handle), |
| base::Unretained(&list))); |
| run_loop.Run(); |
| |
| // Dispatching the event should now reach the default dispatcher. |
| source()->Dispatch(*event); |
| ASSERT_EQ(2u, list.size()); |
| EXPECT_EQ(15, list[0]); |
| EXPECT_EQ(10, list[1]); |
| } |
| }; |
| |
| RUN_TEST_IN_MESSAGE_LOOP( |
| ConsecutiveOverriddenDispatcherInTheSameMessageLoopIteration) |
| |
| } // namespace ui |