Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1042)

Unified Diff: ui/events/event_rewriter_unittest.cc

Issue 210203002: events: Introduce EventRewriter. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..9754552650587dde0aeb86267c85f7f440bd1bc5
--- /dev/null
+++ b/ui/events/event_rewriter_unittest.cc
@@ -0,0 +1,251 @@
+// 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 change and test event type.
+
+// 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() { CheckAllReceived(); }
sadrul 2014/03/24 21:15:38 virtual
+
+ // EventProcessor:
+ virtual EventDispatchDetails OnEventFromSource(Event* event) OVERRIDE {
sadrul 2014/03/24 21:15:38 Overrides typically go at the end of the block. So
+ EXPECT_FALSE(expected_events_.empty());
+ EXPECT_EQ(expected_events_.front(), event->type());
+ expected_events_.pop_front();
+ return EventDispatchDetails();
+ }
+
+ void AddExpectedEvent(EventType type) { expected_events_.push_back(type); }
+ // Test that all expected events have been received.
+ void CheckAllReceived() { EXPECT_TRUE(expected_events_.empty()); }
+
+ private:
+ std::list<EventType> expected_events_;
sadrul 2014/03/24 21:15:38 DISALLOW_COPY_AND_ASSIGN
+};
+
+// Allocates events, testing that none are leaked.
+class TestEventFactory {
+ public:
+ TestEventFactory() {}
+ ~TestEventFactory() { EXPECT_TRUE(events_.empty()); }
+
+ Event* New(EventType type) {
sadrul 2014/03/24 21:15:38 This should return a scoped_ptr<>
+ Event* event = new TestEvent(*this, type);
+ EXPECT_TRUE(event);
+ events_.insert(event);
+ return event;
+ }
+ void Check(Event* event) { EXPECT_NE(events_.end(), events_.find(event)); }
+ void Delete(Event* event) {
+ EventList::iterator find = events_.find(event);
+ EXPECT_NE(events_.end(), find);
+ events_.erase(find);
+ }
+
+ private:
+ class TestEvent : public Event {
+ public:
+ TestEvent(TestEventFactory& factory, EventType type)
+ : Event(type, base::TimeDelta(), 0), factory_(factory) {}
+ ~TestEvent() { factory_.Delete(this); }
+
+ private:
+ TestEventFactory& factory_;
+ };
+ typedef std::set<Event*> EventList;
+ EventList events_;
+ DISALLOW_COPY_AND_ASSIGN(TestEventFactory);
+};
+
+// 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(event_factory_.New(type));
+ (void)SendEventToProcessor(event.get());
sadrul 2014/03/24 21:15:38 You don't need to Delete the event in the event-fa
+ }
+
+ private:
+ TestEventFactory event_factory_;
+ EventProcessor* processor_;
+};
+
+// This EventRewriter always returns the same status; it is used to test
+// simple rewriting, and rewriter addition, removal, and sequencing.
+// EVENT_REWRITE_DISPATCH_ANOTHER is not supported here.
+class TestConstantEventRewriter : public EventRewriter {
+ public:
+ TestConstantEventRewriter(EventRewriteStatus status, EventType type)
+ : status_(status), type_(type) {
+ EXPECT_NE(EVENT_REWRITE_DISPATCH_ANOTHER, status);
sadrul 2014/03/24 21:15:38 CHECK instead
+ }
+
+ virtual EventRewriteStatus RewriteEvent(const Event& event,
+ Event** rewritten_event) OVERRIDE {
+ EXPECT_TRUE(rewritten_event);
+ if (status_ == EVENT_REWRITE_REWRITTEN) {
+ *rewritten_event = event_factory_.New(type_);
+ }
+ return status_;
+ }
+ virtual EventRewriteStatus NextDispatchEvent(const Event& last_event,
+ Event** new_event) OVERRIDE {
+ EXPECT_TRUE(false);
sadrul 2014/03/24 21:15:38 Replace this with a NOTREACHED instead
+ return status_;
+ }
+
+ private:
+ EventRewriteStatus status_;
+ EventType type_;
+ TestEventFactory event_factory_;
+};
+
+// This EventRewriter runs a simple state machine; it is used to test
+// EVENT_REWRITE_DISPATCH_ANOTHER.
+class TestStateMachineEventRewriter : public EventRewriter {
+ public:
+ TestStateMachineEventRewriter() : state_(0), last_rewritten_event_(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,
+ Event** rewritten_event) OVERRIDE {
+ EXPECT_TRUE(rewritten_event);
+ 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_ = event_factory_.New(find->second.type);
+ *rewritten_event = last_rewritten_event_;
+ }
+ state_ = find->second.state;
+ return find->second.status;
+ }
+ virtual EventRewriteStatus NextDispatchEvent(const Event& last_event,
+ Event** new_event) OVERRIDE {
+ EXPECT_TRUE(last_rewritten_event_);
+ EXPECT_EQ(last_rewritten_event_->type(), last_event.type());
+ event_factory_.Check(last_rewritten_event_);
sadrul 2014/03/24 21:15:38 We should add a unique-identifer for each TestEven
kpschoedel 2014/03/25 18:12:01 Is it really necessary to pass back last_event? If
sadrul 2014/03/25 18:24:35 I am thinking the rewriter will need to maintain l
+ last_rewritten_event_ = 0;
+ 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;
+
+ int state_;
+ RewriteRules rules_;
+ TestEventFactory event_factory_;
+ Event* last_rewritten_event_;
+};
+
+} // 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

Powered by Google App Engine
This is Rietveld 408576698