blob: 25a7705f42c37de30816ad167e5e230ee15d0a78 [file] [log] [blame]
// Copyright (c) 2010 The Chromium OS 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 <gflags/gflags.h>
#include <gtest/gtest.h>
#include "base/scoped_ptr.h"
#include "base/logging.h"
#include "window_manager/callback.h"
#include "window_manager/event_loop.h"
#include "window_manager/pointer_position_watcher.h"
#include "window_manager/test_lib.h"
#include "window_manager/x11/mock_x_connection.h"
DEFINE_bool(logtostderr, false,
"Print debugging messages to stderr (suppressed otherwise)");
namespace window_manager {
class PointerPositionWatcherTest : public ::testing::Test {
};
// Struct that contains a watcher and has a method to delete it.
// Used by the DeleteFromCallback test.
struct WatcherContainer {
void set_watcher(PointerPositionWatcher* new_watcher) {
watcher.reset(new_watcher);
}
scoped_ptr<PointerPositionWatcher> watcher;
};
TEST_F(PointerPositionWatcherTest, Basic) {
EventLoop event_loop;
MockXConnection xconn;
xconn.SetPointerPosition(Point(0, 0));
// Watch for the pointer moving into a 20x30 rectangle at (50, 100).
TestCallbackCounter counter;
scoped_ptr<PointerPositionWatcher> watcher(
new PointerPositionWatcher(
&event_loop,
&xconn,
NewPermanentCallback(&counter, &TestCallbackCounter::Increment),
true, // watch_for_entering_target
50, 100, // x, y
20, 30)); // width, height
EXPECT_GE(watcher->timeout_id(), 0);
// Check that the callback doesn't get run and the timer stays active as
// long as the pointer is outside of the rectangle.
watcher->TriggerTimeout();
EXPECT_EQ(0, counter.num_calls());
EXPECT_GE(watcher->timeout_id(), 0);
xconn.SetPointerPosition(Point(49, 105));
watcher->TriggerTimeout();
EXPECT_EQ(0, counter.num_calls());
EXPECT_GE(watcher->timeout_id(), 0);
// As soon as the pointer moves into the rectangle, the callback should
// be run and the timer should be destroyed.
xconn.SetPointerPosition(Point(50, 105));
watcher->TriggerTimeout();
EXPECT_EQ(1, counter.num_calls());
EXPECT_EQ(-1, watcher->timeout_id());
// Now create a new watcher that waits for the pointer to move *outside*
// of the same region.
watcher.reset(
new PointerPositionWatcher(
&event_loop,
&xconn,
NewPermanentCallback(&counter, &TestCallbackCounter::Increment),
false, // watch_for_entering_target=false
50, 100, // x, y
20, 30)); // width, height
EXPECT_GE(watcher->timeout_id(), 0);
counter.Reset();
watcher->TriggerTimeout();
EXPECT_EQ(0, counter.num_calls());
EXPECT_GE(watcher->timeout_id(), 0);
xconn.SetPointerPosition(Point(69, 129));
watcher->TriggerTimeout();
EXPECT_EQ(0, counter.num_calls());
EXPECT_GE(watcher->timeout_id(), 0);
xconn.SetPointerPosition(Point(69, 130));
watcher->TriggerTimeout();
EXPECT_EQ(1, counter.num_calls());
EXPECT_EQ(-1, watcher->timeout_id());
}
// Test that we don't crash if a callback deletes the watcher that ran it.
TEST_F(PointerPositionWatcherTest, DeleteFromCallback) {
EventLoop event_loop;
MockXConnection xconn;
xconn.SetPointerPosition(Point(0, 0));
// Register a callback that deletes its own watcher.
WatcherContainer container;
container.set_watcher(
new PointerPositionWatcher(
&event_loop,
&xconn,
NewPermanentCallback(
&container,
&WatcherContainer::set_watcher,
static_cast<PointerPositionWatcher*>(NULL)),
true, // watch_for_entering_target
0, 0, // x, y
10, 10)); // width, height
container.watcher->TriggerTimeout();
EXPECT_TRUE(container.watcher.get() == NULL);
}
} // namespace window_manager
int main(int argc, char** argv) {
return window_manager::InitAndRunTests(&argc, argv, &FLAGS_logtostderr);
}