blob: 9eae471f3938afeb70b478882fac8c79ac55f903 [file] [log] [blame]
// Copyright 2015 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/scoped_target_handler.h"
#include <memory>
#include <utility>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_handler.h"
#include "ui/events/event_target.h"
#include "ui/events/event_target_iterator.h"
#include "ui/events/event_utils.h"
namespace ui {
namespace {
class TestEventTargetIterator : public EventTargetIterator {
public:
TestEventTargetIterator() {}
// EventTargetIterator:
EventTarget* GetNextTarget() override { return nullptr; }
private:
DISALLOW_COPY_AND_ASSIGN(TestEventTargetIterator);
};
// An EventTarget that holds ownership of its target and delegate EventHandlers.
class TestEventTarget : public EventTarget {
public:
TestEventTarget() {}
~TestEventTarget() override {}
void SetHandler(std::unique_ptr<EventHandler> target_handler,
std::unique_ptr<EventHandler> delegate) {
target_handler_ = std::move(target_handler);
delegate_ = std::move(delegate);
}
// EventTarget:
void DispatchEvent(Event* event) { target_handler()->OnEvent(event); }
bool CanAcceptEvent(const Event& event) override { return true; }
EventTarget* GetParentTarget() override { return nullptr; }
std::unique_ptr<EventTargetIterator> GetChildIterator() const override {
return base::WrapUnique(new TestEventTargetIterator);
}
EventTargeter* GetEventTargeter() override { return nullptr; }
private:
std::unique_ptr<EventHandler> target_handler_;
std::unique_ptr<EventHandler> delegate_;
DISALLOW_COPY_AND_ASSIGN(TestEventTarget);
};
// An EventHandler that sets itself as a target handler for an EventTarget and
// can recursively dispatch an Event.
class NestedEventHandler : public EventHandler {
public:
NestedEventHandler(TestEventTarget* target, int nesting)
: target_(target), nesting_(nesting) {
original_handler_ = target_->SetTargetHandler(this);
}
~NestedEventHandler() override {
EventHandler* handler = target_->SetTargetHandler(original_handler_);
DCHECK_EQ(this, handler);
}
protected:
void OnEvent(Event* event) override {
if (--nesting_ == 0)
return;
target_->DispatchEvent(event);
}
private:
TestEventTarget* target_;
int nesting_;
EventHandler* original_handler_;
DISALLOW_COPY_AND_ASSIGN(NestedEventHandler);
};
// An EventHandler that sets itself as a target handler for an EventTarget and
// destroys that EventTarget when handling an Event, possibly after recursively
// handling the Event.
class TargetDestroyingEventHandler : public EventHandler {
public:
TargetDestroyingEventHandler(TestEventTarget* target, int nesting)
: target_(target), nesting_(nesting) {
original_handler_ = target_->SetTargetHandler(this);
}
~TargetDestroyingEventHandler() override {
EventHandler* handler = target_->SetTargetHandler(original_handler_);
DCHECK_EQ(this, handler);
}
protected:
void OnEvent(Event* event) override {
if (--nesting_ == 0) {
delete target_;
return;
}
target_->DispatchEvent(event);
}
private:
TestEventTarget* target_;
int nesting_;
EventHandler* original_handler_;
DISALLOW_COPY_AND_ASSIGN(TargetDestroyingEventHandler);
};
// An EventHandler that can be set to receive events in addition to the target
// handler and counts the Events that it receives.
class EventCountingEventHandler : public EventHandler {
public:
EventCountingEventHandler(EventTarget* target, int* count)
: scoped_target_handler_(new ScopedTargetHandler(target, this)),
count_(count) {}
~EventCountingEventHandler() override {}
protected:
void OnEvent(Event* event) override { (*count_)++; }
private:
std::unique_ptr<ScopedTargetHandler> scoped_target_handler_;
int* count_;
DISALLOW_COPY_AND_ASSIGN(EventCountingEventHandler);
};
} // namespace
// Tests that a ScopedTargetHandler invokes both the target and a delegate.
TEST(ScopedTargetHandlerTest, HandlerInvoked) {
int count = 0;
TestEventTarget* target = new TestEventTarget;
std::unique_ptr<NestedEventHandler> target_handler(
new NestedEventHandler(target, 1));
std::unique_ptr<EventCountingEventHandler> delegate(
new EventCountingEventHandler(target, &count));
target->SetHandler(std::move(target_handler), std::move(delegate));
MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
EventTimeForNow(), EF_LEFT_MOUSE_BUTTON,
EF_LEFT_MOUSE_BUTTON);
target->DispatchEvent(&event);
EXPECT_EQ(1, count);
delete target;
}
// Tests that a ScopedTargetHandler invokes both the target and a delegate when
// an Event is dispatched recursively such as with synthetic events.
TEST(ScopedTargetHandlerTest, HandlerInvokedNested) {
int count = 0;
TestEventTarget* target = new TestEventTarget;
std::unique_ptr<NestedEventHandler> target_handler(
new NestedEventHandler(target, 2));
std::unique_ptr<EventCountingEventHandler> delegate(
new EventCountingEventHandler(target, &count));
target->SetHandler(std::move(target_handler), std::move(delegate));
MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
EventTimeForNow(), EF_LEFT_MOUSE_BUTTON,
EF_LEFT_MOUSE_BUTTON);
target->DispatchEvent(&event);
EXPECT_EQ(2, count);
delete target;
}
// Tests that a it is safe to delete a ScopedTargetHandler while handling an
// event.
TEST(ScopedTargetHandlerTest, SafeToDestroy) {
int count = 0;
TestEventTarget* target = new TestEventTarget;
std::unique_ptr<TargetDestroyingEventHandler> target_handler(
new TargetDestroyingEventHandler(target, 1));
std::unique_ptr<EventCountingEventHandler> delegate(
new EventCountingEventHandler(target, &count));
target->SetHandler(std::move(target_handler), std::move(delegate));
MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
EventTimeForNow(), EF_LEFT_MOUSE_BUTTON,
EF_LEFT_MOUSE_BUTTON);
target->DispatchEvent(&event);
EXPECT_EQ(0, count);
}
// Tests that a it is safe to delete a ScopedTargetHandler while handling an
// event recursively.
TEST(ScopedTargetHandlerTest, SafeToDestroyNested) {
int count = 0;
TestEventTarget* target = new TestEventTarget;
std::unique_ptr<TargetDestroyingEventHandler> target_handler(
new TargetDestroyingEventHandler(target, 2));
std::unique_ptr<EventCountingEventHandler> delegate(
new EventCountingEventHandler(target, &count));
target->SetHandler(std::move(target_handler), std::move(delegate));
MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
EventTimeForNow(), EF_LEFT_MOUSE_BUTTON,
EF_LEFT_MOUSE_BUTTON);
target->DispatchEvent(&event);
EXPECT_EQ(0, count);
}
} // namespace ui