What is WLCS: A protocol-conformance test suite for Wayland compositors. Unlike previous test suites that use protocol extensions, WLCS uses compositor-provided integration modules loaded as shared libraries (.so files). Tests run in-process with the compositor, enabling easier debugging and consistent timing.
Core Components:
include/wlcs/display_server.h: Integration API that compositors must implement (WlcsServerIntegration, WlcsDisplayServer structs)src/: Test infrastructure (test runner, client/server helpers, protocol wrappers)tests/: Protocol conformance tests for wl_compositor, xdg_shell, layer_shell, input methods, etc.example/mir_integration.cpp: Reference integration showing how Mir implements the WLCS APIKey Pattern: Compositors provide a wlcs_server_integration symbol in their integration .so. WLCS loads this and calls hooks to start/stop the compositor, create client sockets, inject input, etc.
Base Classes (see include/in_process_server.h):
InProcessServer: GTest fixture that creates a Server instance. Use SetUp()/TearDown() explicitlyStartedInProcessServer: Auto-starts the server in constructor. Most tests inherit from thisCreating Test Clients:
wlcs::Client client{the_server()}; // Creates Wayland client connection wlcs::Surface surface{client}; // Creates wl_surface client.roundtrip(); // Block until server processes requests
Simulating Input (see include/wlcs/pointer.h, include/wlcs/touch.h, include/wlcs/keyboard.h):
auto pointer = the_server().create_pointer(); pointer.move_to(100, 200); // Absolute coordinates pointer.left_click(); auto touch = the_server().create_touch(); touch.down_at(50, 50); touch.move_to(60, 60); touch.up(); auto keyboard = the_server().create_keyboard(); keyboard.key_down(KEY_A); // Linux input event codes keyboard.key_up(KEY_A); keyboard.key(KEY_ENTER); // Press and release
Protocol Wrappers: Headers like layer_shell_v1.h, xdg_shell_stable.h provide RAII wrappers around Wayland protocols with helper methods (e.g., dispatch_until_configure()).
Parameterized Tests: Many tests use TEST_P to run across multiple shell types or input devices. See tests/subsurfaces.cpp for the pattern using AbstractInputDevice abstraction.
Follow the Canonical Mir C++ Guide.
Requirements:
CMAKE_CXX_STANDARD 20)-Werror enabled by default (toggle with WLCS_FATAL_COMPILE_WARNINGS)Key Conventions:
#ifndef WLCS_*_H_)WlHandle<T> in wl_handle.h)wlcs::helpers::a_short_time() (for negative tests), wlcs::helpers::a_long_time() (for operation timeouts)Testing Protocol Errors: Use expect_protocol_error.h to verify compositor rejects invalid client requests:
EXPECT_PROTOCOL_ERROR(client, &interface_name, error_code, { // code that should trigger error });
Adding Protocol Tests:
.xml to src/protocol/ if not presentinclude/ (follow pattern from layer_shell_v1.h)src/ (generate protocol bindings in CMake)tests/ inheriting from StartedInProcessServerProtocol Version Handling: Use VersionSpecifier (see version_specifier.h) to bind interfaces:
auto shell = client.bind_if_supported<xdg_wm_base>(wlcs::AtLeast(2));