| Index: ui/events/event_rewriter_unittest.cc
|
| diff --git a/ui/events/event_rewriter_unittest.cc b/ui/events/event_rewriter_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e06630a01432fdbf995de222856cfe21cb598c32
|
| --- /dev/null
|
| +++ b/ui/events/event_rewriter_unittest.cc
|
| @@ -0,0 +1,229 @@
|
| +// Copyright (c) 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/event_rewriter.h"
|
| +
|
| +#include <list>
|
| +#include <map>
|
| +#include <set>
|
| +#include <utility>
|
| +
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "ui/events/test/test_event_processor.h"
|
| +
|
| +namespace ui {
|
| +
|
| +namespace {
|
| +
|
| +// To test the handling of |EventRewriter|s through |EventSource|,
|
| +// we rewrite and test event types.
|
| +class TestEvent : public Event {
|
| + public:
|
| + explicit TestEvent(EventType type)
|
| + : Event(type, base::TimeDelta(), 0), unique_id_(next_unique_id_++) {}
|
| + ~TestEvent() {}
|
| + int unique_id() const { return unique_id_; }
|
| +
|
| + private:
|
| + static int next_unique_id_;
|
| + int unique_id_;
|
| +};
|
| +
|
| +int TestEvent::next_unique_id_ = 0;
|
| +
|
| +// TestEventRewriteProcessor is set up with a sequence of event types,
|
| +// and fails if the events received via OnEventFromSource() do not match
|
| +// this sequence. These expected event types are consumed on receipt.
|
| +class TestEventRewriteProcessor : public test::TestEventProcessor {
|
| + public:
|
| + TestEventRewriteProcessor() {}
|
| + virtual ~TestEventRewriteProcessor() { CheckAllReceived(); }
|
| +
|
| + void AddExpectedEvent(EventType type) { expected_events_.push_back(type); }
|
| + // Test that all expected events have been received.
|
| + void CheckAllReceived() { EXPECT_TRUE(expected_events_.empty()); }
|
| +
|
| + // EventProcessor:
|
| + virtual EventDispatchDetails OnEventFromSource(Event* event) OVERRIDE {
|
| + EXPECT_FALSE(expected_events_.empty());
|
| + EXPECT_EQ(expected_events_.front(), event->type());
|
| + expected_events_.pop_front();
|
| + return EventDispatchDetails();
|
| + }
|
| +
|
| + private:
|
| + std::list<EventType> expected_events_;
|
| + DISALLOW_COPY_AND_ASSIGN(TestEventRewriteProcessor);
|
| +};
|
| +
|
| +// Trivial EventSource that does nothing but send events.
|
| +class TestEventRewriteSource : public EventSource {
|
| + public:
|
| + explicit TestEventRewriteSource(EventProcessor* processor)
|
| + : processor_(processor) {}
|
| + virtual EventProcessor* GetEventProcessor() OVERRIDE { return processor_; }
|
| + void Send(EventType type) {
|
| + scoped_ptr<Event> event(new TestEvent(type));
|
| + (void)SendEventToProcessor(event.get());
|
| + }
|
| +
|
| + private:
|
| + EventProcessor* processor_;
|
| +};
|
| +
|
| +// This EventRewriter always returns the same status, and if rewriting, the
|
| +// same event type; it is used to test simple rewriting, and rewriter addition,
|
| +// removal, and sequencing. Consequently EVENT_REWRITE_DISPATCH_ANOTHER is not
|
| +// supported here (calls to NextDispatchEvent() would continue indefinitely).
|
| +class TestConstantEventRewriter : public EventRewriter {
|
| + public:
|
| + TestConstantEventRewriter(EventRewriteStatus status, EventType type)
|
| + : status_(status), type_(type) {
|
| + CHECK_NE(EVENT_REWRITE_DISPATCH_ANOTHER, status);
|
| + }
|
| +
|
| + virtual EventRewriteStatus RewriteEvent(
|
| + const Event& event, scoped_ptr<Event>& rewritten_event) OVERRIDE {
|
| + if (status_ == EVENT_REWRITE_REWRITTEN) {
|
| + rewritten_event.reset(new TestEvent(type_));
|
| + }
|
| + return status_;
|
| + }
|
| + virtual EventRewriteStatus NextDispatchEvent(
|
| + const Event& last_event, scoped_ptr<Event>& new_event) OVERRIDE {
|
| + NOTREACHED();
|
| + return status_;
|
| + }
|
| +
|
| + private:
|
| + EventRewriteStatus status_;
|
| + EventType type_;
|
| +};
|
| +
|
| +// This EventRewriter runs a simple state machine; it is used to test
|
| +// EVENT_REWRITE_DISPATCH_ANOTHER.
|
| +class TestStateMachineEventRewriter : public EventRewriter {
|
| + public:
|
| + TestStateMachineEventRewriter() : last_rewritten_event_(0), state_(0) {}
|
| + void AddRule(int from_state, EventType from_type, int to_state,
|
| + EventType to_type, EventRewriteStatus to_status) {
|
| + RewriteResult r = {to_state, to_type, to_status};
|
| + rules_.insert(std::pair<RewriteCase, RewriteResult>(
|
| + RewriteCase(from_state, from_type), r));
|
| + }
|
| + virtual EventRewriteStatus RewriteEvent(
|
| + const Event& event, scoped_ptr<Event>& rewritten_event) OVERRIDE {
|
| + RewriteRules::iterator find =
|
| + rules_.find(RewriteCase(state_, event.type()));
|
| + if (find == rules_.end()) {
|
| + return EVENT_REWRITE_CONTINUE;
|
| + }
|
| + if ((find->second.status == EVENT_REWRITE_REWRITTEN) ||
|
| + (find->second.status == EVENT_REWRITE_DISPATCH_ANOTHER)) {
|
| + last_rewritten_event_ = new TestEvent(find->second.type);
|
| + rewritten_event.reset(last_rewritten_event_);
|
| + } else {
|
| + last_rewritten_event_ = 0;
|
| + }
|
| + state_ = find->second.state;
|
| + return find->second.status;
|
| + }
|
| + virtual EventRewriteStatus NextDispatchEvent(
|
| + const Event& last_event, scoped_ptr<Event>& new_event) OVERRIDE {
|
| + EXPECT_TRUE(last_rewritten_event_);
|
| + const TestEvent* arg_last = static_cast<const TestEvent*>(&last_event);
|
| + EXPECT_EQ(last_rewritten_event_->unique_id(), arg_last->unique_id());
|
| + const TestEvent* arg_new = static_cast<const TestEvent*>(new_event.get());
|
| + EXPECT_FALSE(new_event && arg_last->unique_id() == arg_new->unique_id());
|
| + return RewriteEvent(last_event, new_event);
|
| + }
|
| +
|
| + private:
|
| + typedef std::pair<int, EventType> RewriteCase;
|
| + struct RewriteResult {
|
| + int state;
|
| + EventType type;
|
| + EventRewriteStatus status;
|
| + };
|
| + typedef std::map<RewriteCase, RewriteResult> RewriteRules;
|
| + RewriteRules rules_;
|
| + TestEvent* last_rewritten_event_;
|
| + int state_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +TEST(EventRewriterTest, EventRewriting) {
|
| + // TestEventRewriter r0 always rewrites events to ET_CANCEL_MODE;
|
| + // it is placed at the beginning of the chain and later removed,
|
| + // to verify that rewriter removal works.
|
| + TestConstantEventRewriter r0(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);
|
| +
|
| + // TestEventRewriter r1 always returns EVENT_REWRITE_CONTINUE;
|
| + // it is placed at the beginning of the chain to verify that a
|
| + // later rewriter sees the events.
|
| + TestConstantEventRewriter r1(EVENT_REWRITE_CONTINUE, ET_UNKNOWN);
|
| +
|
| + // TestEventRewriter r2 has a state machine, primarily to test
|
| + // |EVENT_REWRITE_DISPATCH_ANOTHER|.
|
| + TestStateMachineEventRewriter r2;
|
| +
|
| + // TestEventRewriter r3 always rewrites events to ET_CANCEL_MODE;
|
| + // it is placed at the end of the chain to verify that previously
|
| + // rewritten events are not passed further down the chain.
|
| + TestConstantEventRewriter r3(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);
|
| +
|
| + TestEventRewriteProcessor p;
|
| + TestEventRewriteSource s(&p);
|
| + s.AddEventRewriter(&r0);
|
| + s.AddEventRewriter(&r1);
|
| + s.AddEventRewriter(&r2);
|
| +
|
| + // These events should be rewritten by r0 to ET_CANCEL_MODE.
|
| + p.AddExpectedEvent(ET_CANCEL_MODE);
|
| + s.Send(ET_MOUSE_DRAGGED);
|
| + p.AddExpectedEvent(ET_CANCEL_MODE);
|
| + s.Send(ET_MOUSE_PRESSED);
|
| + p.CheckAllReceived();
|
| +
|
| + // Remove r0, and verify that it's gone and that events make it through.
|
| + s.AddEventRewriter(&r3);
|
| + s.RemoveEventRewriter(&r0);
|
| + r2.AddRule(0, ET_SCROLL_FLING_START, 0, ET_SCROLL_FLING_CANCEL,
|
| + EVENT_REWRITE_REWRITTEN);
|
| + p.AddExpectedEvent(ET_SCROLL_FLING_CANCEL);
|
| + s.Send(ET_SCROLL_FLING_START);
|
| + p.CheckAllReceived();
|
| + s.RemoveEventRewriter(&r3);
|
| +
|
| + // Verify EVENT_REWRITE_DISPATCH_ANOTHER using a state machine
|
| + // (that happens to be analogous to sticky keys).
|
| + r2.AddRule(0, ET_KEY_PRESSED,
|
| + 1, ET_KEY_PRESSED, EVENT_REWRITE_CONTINUE);
|
| + r2.AddRule(1, ET_MOUSE_PRESSED,
|
| + 0, ET_MOUSE_PRESSED, EVENT_REWRITE_CONTINUE);
|
| + r2.AddRule(1, ET_KEY_RELEASED,
|
| + 2, ET_KEY_RELEASED, EVENT_REWRITE_DISCARD);
|
| + r2.AddRule(2, ET_MOUSE_RELEASED,
|
| + 3, ET_MOUSE_RELEASED, EVENT_REWRITE_DISPATCH_ANOTHER);
|
| + r2.AddRule(3, ET_MOUSE_RELEASED,
|
| + 0, ET_KEY_RELEASED, EVENT_REWRITE_REWRITTEN);
|
| + p.AddExpectedEvent(ET_KEY_PRESSED);
|
| + s.Send(ET_KEY_PRESSED);
|
| + s.Send(ET_KEY_RELEASED);
|
| + p.AddExpectedEvent(ET_MOUSE_PRESSED);
|
| + s.Send(ET_MOUSE_PRESSED);
|
| +
|
| + // Removing rewriters r1 and r3 shouldn't affect r2.
|
| + s.RemoveEventRewriter(&r1);
|
| + s.RemoveEventRewriter(&r3);
|
| +
|
| + // Continue with the state-based rewriting.
|
| + p.AddExpectedEvent(ET_MOUSE_RELEASED);
|
| + p.AddExpectedEvent(ET_KEY_RELEASED);
|
| + s.Send(ET_MOUSE_RELEASED);
|
| + p.CheckAllReceived();
|
| +}
|
| +
|
| +} // namespace ui
|
|
|