blob: 3d9d9e73cb2f1f176f4046a57ed638ff03599c77 [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.
#ifndef WINDOW_MANAGER_TEST_LIB_H_
#define WINDOW_MANAGER_TEST_LIB_H_
#include <string>
#include <gtest/gtest.h>
extern "C" {
#include <X11/Xlib.h>
}
#include "base/file_path.h"
#include "base/scoped_ptr.h"
#include "base/logging.h"
#include "cros/chromeos_wm_ipc_enums.h"
#include "window_manager/compositor/gl/mock_gl_interface.h"
#include "window_manager/compositor/mock_compositor.h"
#include "window_manager/compositor/real_compositor.h"
#include "window_manager/event_consumer.h"
#include "window_manager/event_loop.h"
#include "window_manager/key_bindings.h"
#include "window_manager/mock_dbus_interface.h"
#include "window_manager/stacking_manager.h"
#include "window_manager/window_manager.h"
#include "window_manager/wm_ipc.h"
#include "window_manager/x11/mock_x_connection.h"
#include "window_manager/x11/x_types.h"
namespace window_manager {
class Panel;
// Test that two bytes sequences are equal, pretty-printing the difference
// otherwise. Invoke as:
//
// EXPECT_PRED_FORMAT3(BytesAreEqual, expected, actual, length);
//
testing::AssertionResult BytesAreEqual(
const char* expected_expr,
const char* actual_expr,
const char* size_expr,
const unsigned char* expected,
const unsigned char* actual,
size_t size);
// Called from tests' main() functions to handle a bunch of boilerplate.
// Its return value should be returned from main(). We initialize the
// flag-parsing code, so if the caller wants to set |log_to_stderr| based
// on a flag, a pointer to the flag's variable should be passed here (e.g.
// |&FLAGS_logtostderr|).
int InitAndRunTests(int* argc, char** argv, bool* log_to_stderr);
// A basic test that sets up fake X and compositor interfaces and creates a
// WindowManager object. Also includes several methods that tests can use
// for convenience.
class BasicWindowManagerTest : public ::testing::Test {
protected:
// Simple RAII class for creating and deleting a temporary directory.
class ScopedTempDirectory {
public:
ScopedTempDirectory();
~ScopedTempDirectory();
const FilePath& path() const { return path_; }
private:
FilePath path_;
};
virtual void SetUp();
// Register keycodes corresponding to common keysyms.
void RegisterCommonKeySyms();
// Create a new WindowManager object using the existing X connection,
// compositor, etc. and store it in |wm_|.
void CreateNewWm();
// Call CreateNewWm() and then call its Init() method and ensure that it
// succeeds.
void CreateAndInitNewWm();
// Create a basic window with no special type.
XWindow CreateBasicWindow(int x, int y, int width, int height);
// Create a toplevel client window with the passed-in position and
// dimensions. It has type WINDOW_TYPE_CHROME_TOPLEVEL.
XWindow CreateToplevelWindow(int tab_count, int selected_tab,
int x, int y, int width, int height);
// Create a snapshot client window with the passed-in position and
// dimensions and associated parent toplevel window.
XWindow CreateSnapshotWindow(XWindow parent_xid, int index,
int x, int y,
int width, int height);
// Creates a fav icon window for the associated snapshot.
XWindow CreateFavIconWindow(XWindow snapshot_xid,
int width, int height);
// Creates a title window for the associated snapshot.
XWindow CreateTitleWindow(XWindow snapshot_xid,
int width, int height);
// Creates a decoration window (favicon or title) for the associated
// snapshot window.
XWindow CreateDecorationWindow(XWindow snapshot_xid,
chromeos::WmIpcWindowType type,
int width, int height);
// Creates a toplevel client window with an arbitrary size.
XWindow CreateSimpleWindow();
// Creates a snapshot client window with an arbitrary size.
// |toplevel_xid| is the id of the associated toplevel window.
// |index| is the index of the snapshot within the given toplevel
// window.
XWindow CreateSimpleSnapshotWindow(XWindow toplevel_xid, int index);
// Create a panel titlebar or content window. Muck around with the
// |*new_panel*| members below to change content window parameters.
XWindow CreatePanelTitlebarWindow(int width, int height);
XWindow CreatePanelContentWindow(int width, int height, XWindow titlebar_xid);
// Create titlebar and content windows for a panel, show them, and return
// a pointer to the Panel object.
Panel* CreatePanel(int width, int titlebar_height, int content_height);
// Simulates a change in the selected tab and tab count in a chrome
// toplevel window.
void ChangeTabInfo(XWindow toplevel_xid,
int tab_count,
int selected_tab,
uint32_t timestamp);
// Make the window manager handle a CreateNotify event and, if the window
// isn't override-redirect, a MapRequest. If it's mapped after this
// (expected if we sent a MapRequest), send a MapNotify event. After
// each event, we send a ConfigureNotify if the window manager changed
// something about the window using a ConfigureWindow request.
void SendInitialEventsForWindow(XWindow xid);
// Send UnmapNotify and DestroyWindow events to the window manager.
void SendUnmapAndDestroyEventsForWindow(XWindow xid);
// Send a property change notification for the Chrome window type.
void SendWindowTypeEvent(XWindow xid);
// Send a WmIpc message.
void SendWmIpcMessage(const WmIpc::Message& msg);
// Send a WM_NOTIFY_IPC_VERSION message.
void SendNotifyIpcVersionMessage(int version);
// Send a WM_SET_PANEL_STATE message.
void SendSetPanelStateMessage(Panel* panel, bool expanded);
// Send a WM_NOTIFY_PANEL_DRAGGED message.
void SendPanelDraggedMessage(Panel* panel, int x, int y);
// Send a WM_NOTIFY_PANEL_DRAG_COMPLETE message.
void SendPanelDragCompleteMessage(Panel* panel);
// Send a WM_IPC_MESSAGE_WM_SET_LOGIN_STATE message telling the window
// manager that the login entries should be selectable or not.
void SendSetLoginStateMessage(bool entries_selectable);
// Send a key press and release to the given xid.
void SendKey(XWindow xid,
KeyBindings::KeyCombo key,
XTime press_timestamp,
XTime release_timestamp);
// Send a _NET_ACTIVE_WINDOW message asking the window manager to focus a
// window.
void SendActiveWindowMessage(XWindow xid);
// Invoke Window::HandleConfigureNotify() using the client window's size.
// The Window class defers resizing its actor until it sees a
// ConfigureNotify event; this can be used to make sure that the actor's
// size matches the current client size.
void NotifyWindowAboutSize(Window* win);
// Set the _CHROME_LOGGED_IN property on the root window to describe
// whether Chrome is logged in or not, and send a PropertyNotify event to
// the window manager (if it's non-NULL).
void SetLoggedInState(bool logged_in);
// Append an atom to an integer property on a window.
void AppendAtomToProperty(
XWindow xid, XAtom property_atom, XAtom atom_to_add);
// Configure a window to use the _NET_WM_SYNC_REQUEST protocol to
// synchronize repaints in response to resizes. Adds the
// _NET_WM_SYNC_REQUEST hint to the window's WM_PROTOCOLS property and
// sets its _NET_WM_SYNC_REQUEST_COUNTER property.
void ConfigureWindowForSyncRequestProtocol(XWindow xid);
// Send the window manager an event telling it that the alarm that it's
// using to wait for notification that a client has finished repainting a
// window has fired.
void SendSyncRequestProtocolAlarm(XWindow xid);
// Get the current value of the _NET_ACTIVE_WINDOW property on the root
// window.
XWindow GetActiveWindowProperty();
// Get the number of WM_DELETE_WINDOW messages that have been sent to a
// window.
int GetNumDeleteWindowMessagesForWindow(XWindow xid);
// Get the first WmIpc message of a particular type received by a window.
// Returns false if no messages of that type were found.
bool GetFirstWmIpcMessageOfType(XWindow xid,
chromeos::WmIpcMessageType type,
WmIpc::Message* msg_out);
// Are the passed-in window's composited and client windows stacked
// between the passed-in layer and the layer underneath it?
bool WindowIsInLayer(Window* win, StackingManager::Layer layer);
// Is the passed-in client window entirely offscreen?
bool WindowIsOffscreen(XWindow xid);
// Fetch an int array property on a window and check that it contains the
// expected values. |num_values| is the number of expected values passed
// as varargs.
void TestIntArrayProperty(XWindow xid, XAtom atom, int num_values, ...);
// Test the bounds of a panel's content window.
void TestPanelContentBounds(
Panel* panel, int x, int y, int width, int height);
// Are a panel's client and composited windows at the same spot?
bool PanelClientAndCompositedWindowsHaveSamePositions(Panel* panel);
// Decode the message from |event| into |msg|. Returns false on failure.
bool DecodeWmIpcMessage(const XClientMessageEvent& event,
WmIpc::Message* msg_out);
// Get the mock actor for the passed-in window.
MockCompositor::TexturePixmapActor* GetMockActorForWindow(Window* win);
// Fills the rect specified with bounds of composited window attached to
// specified xid.
void GetCompositedWindowBounds(XWindow xid, Rect* bounds) const;
scoped_ptr<EventLoop> event_loop_;
scoped_ptr<MockXConnection> xconn_;
scoped_ptr<MockCompositor> compositor_;
scoped_ptr<MockDBusInterface> dbus_;
scoped_ptr<WindowManager> wm_;
// Settings used for subsequent windows created by
// CreatePanelContentWindow() and CreatePanel(). These are here so that
// new parameters can be added without having to update a bunch of
// testing code (tests for the new parameters can change these settings,
// while existing tests can just use reasonably-chosen defaults).
bool new_panels_should_be_expanded_;
bool new_panels_should_take_focus_;
XWindow creator_content_xid_for_new_panels_;
chromeos::WmIpcPanelUserResizeType resize_type_for_new_panels_;
};
// Base class for compositing-related tests.
class BasicCompositingTest : public ::testing::Test {
public:
BasicCompositingTest() {}
virtual ~BasicCompositingTest();
virtual void SetUp();
virtual void TearDown() {}
protected:
scoped_ptr<MockGLInterface> gl_;
scoped_ptr<MockXConnection> xconn_;
scoped_ptr<EventLoop> event_loop_;
scoped_ptr<RealCompositor> compositor_;
};
class BasicCompositingTreeTest : public BasicCompositingTest {
public:
BasicCompositingTreeTest() {}
virtual ~BasicCompositingTreeTest();
virtual void SetUp();
virtual void TearDown() { BasicCompositingTest::TearDown(); }
protected:
// stage
// | |
// group1 group3
// | |
// group2 group4
// | | |
// rect1 rect2 rect3
//
// A container (with the exception of the stage)'s depth is further away
// than that of its children, and earlier-added children within each
// container will be further away than later-added children.
//
// Given the order in which these actors are added in test_lib.cc, the
// depths (in nearest to furthest order) should be:
//
// stage 0
// rect3 256
// rect2 (culled)
// group4 512
// group3 768
// rect1 (culled)
// group2 1024
// group1 1280
RealCompositor::StageActor* stage_;
scoped_ptr<RealCompositor::ContainerActor> group1_;
scoped_ptr<RealCompositor::ContainerActor> group2_;
scoped_ptr<RealCompositor::ContainerActor> group3_;
scoped_ptr<RealCompositor::ContainerActor> group4_;
scoped_ptr<RealCompositor::ColoredBoxActor> rect1_;
scoped_ptr<RealCompositor::ColoredBoxActor> rect2_;
scoped_ptr<RealCompositor::ColoredBoxActor> rect3_;
};
// Simple class that can be used to test callback invocation.
class TestCallbackCounter {
public:
TestCallbackCounter() : num_calls_(0) {}
int num_calls() const { return num_calls_; }
void Reset() { num_calls_ = 0; }
void Increment() { num_calls_++; }
private:
// Number of times that Increment() has been invoked.
int num_calls_;
};
class TestEventConsumer : public EventConsumer {
public:
TestEventConsumer()
: EventConsumer(),
should_return_true_for_map_requests_(false) {
reset_stats();
}
void reset_stats() {
num_logged_in_state_changes_ = 0;
num_map_requests_ = 0;
num_mapped_windows_ = 0;
num_unmapped_windows_ = 0;
num_initial_pixmaps_ = 0;
num_button_presses_ = 0;
}
void set_should_return_true_for_map_requests(bool return_true) {
should_return_true_for_map_requests_ = return_true;
}
int num_logged_in_state_changes() const {
return num_logged_in_state_changes_;
}
int num_map_requests() const { return num_map_requests_; }
int num_mapped_windows() const { return num_mapped_windows_; }
int num_unmapped_windows() const { return num_unmapped_windows_; }
int num_initial_pixmaps() const { return num_initial_pixmaps_; }
int num_button_presses() const { return num_button_presses_; }
const std::vector<WmIpc::Message>& chrome_messages() const {
return chrome_messages_;
}
const std::set<std::tr1::shared_ptr<DestroyedWindow> >&
destroyed_windows() const {
return destroyed_windows_;
}
// Begin overridden EventConsumer virtual methods.
virtual bool IsInputWindow(XWindow xid) { return false; }
virtual void HandleScreenResize() {}
virtual void HandleLoggedInStateChange() { num_logged_in_state_changes_++; }
virtual bool HandleWindowMapRequest(Window* win) {
num_map_requests_++;
return should_return_true_for_map_requests_;
}
virtual void HandleWindowMap(Window* win) { num_mapped_windows_++; }
virtual void HandleWindowUnmap(Window* win) { num_unmapped_windows_++; }
virtual void HandleWindowInitialPixmap(Window* win) {
num_initial_pixmaps_++;
}
virtual void HandleWindowConfigureRequest(Window* win,
int req_x, int req_y,
int req_width, int req_height) {}
virtual void HandleButtonPress(XWindow xid,
int x, int y,
int x_root, int y_root,
int button,
XTime timestamp) {
num_button_presses_++;
}
virtual void HandleButtonRelease(XWindow xid,
int x, int y,
int x_root, int y_root,
int button,
XTime timestamp) {}
virtual void HandlePointerEnter(XWindow xid,
int x, int y,
int x_root, int y_root,
XTime timestamp) {}
virtual void HandlePointerLeave(XWindow xid,
int x, int y,
int x_root, int y_root,
XTime timestamp) {}
virtual void HandlePointerMotion(XWindow xid,
int x, int y,
int x_root, int y_root,
XTime timestamp) {}
virtual void HandleChromeMessage(const WmIpc::Message& msg) {
chrome_messages_.push_back(msg);
}
virtual void HandleClientMessage(XWindow xid,
XAtom message_type,
const long data[5]) {}
virtual void HandleFocusChange(XWindow xid, bool focus_in) {}
virtual void HandleWindowPropertyChange(XWindow xid, XAtom xatom) {}
virtual void OwnDestroyedWindow(DestroyedWindow* destroyed_win, XWindow xid) {
destroyed_windows_.insert(
std::tr1::shared_ptr<DestroyedWindow>(destroyed_win));
}
// End overridden EventConsumer virtual methods.
private:
// Should we return true when HandleWindowMapRequest() is invoked?
bool should_return_true_for_map_requests_;
int num_logged_in_state_changes_;
int num_map_requests_;
int num_mapped_windows_;
int num_unmapped_windows_;
int num_initial_pixmaps_;
int num_button_presses_;
// Messages received via HandleChromeMessage().
std::vector<WmIpc::Message> chrome_messages_;
// DestroyedWindow objects that WindowManager has given to us.
std::set<std::tr1::shared_ptr<DestroyedWindow> > destroyed_windows_;
};
} // namespace window_manager
#endif // WINDOW_MANAGER_TEST_LIB_H_