1# GTK Layer Shell tests
2This directory is home to the gtk-layer-shell test suite.
3
4## To run tests
5`ninja -C build test` (where `build` is the path to your build directory).
6
7### To add a new integration test
81. Copy an existing integration test file
92. Implement your test as a series of one or more callbacks
103. Add its name to the list in `test/integration-tests/meson.build`
11
12## Scrpts
13- `check-licenses.py` makes sure all files have licenses at the top
14- `tests-not-enabled.py` is only run if tests are disabled, and explains to the user how to enable them
15- `run-integration-test.py` runs a single integration test
16- `check-all-tests-are-in-meson.py` fails if any test files exist that haven't been added to meson (an easy mistake to make)
17
18## Integration tests
19Most of the potential bugs in GTK Layer Shell arise from interactions between the library, GTK and the Wayland compositor, so unit tests aren't particularly useful. Instead, most of our tests are integration tests.
20
21### Integration test app
22Each integration test is a single unique GTK app that uses GTK Layer Shell. All test clients are located in `integration-tests`. Anything common to multiple tests gets pulled into `integration-test-common` or `test-common`. Tests consist of a sequence of callbacks. At the start of each callback the app can state that specific Wayland messages should be sent during or after the callback is run (see expectations format below). Each meson test runs a single integration test.
23
24Integration tests can be run directly on a normal Wayland compositor (this may be useful for debugging). When run without arguments, they open an additional layer shell window with a `Continue ->` button to manually advance the test. Pass `--auto` to run each test callback with a timeout the way they are run when automated.
25
26### Expectations format
27Integration tests emit protocol expectations by using the `EXPECT_MESSAGE` macro. Each expectation is a white-space-separated sequence of tokens written to a line of stdout. The first element must be `EXPECT:` (this is automatically inserted by `EXPECT_MESSAGE`). For an expectation to match a message, each following token must appear in order in the message line. The list of expected messages must match in the correct order. Messages are matched against the output of the app run with `WAYLAND_DEBUG=1`. Events and requests are not distinguished.
28
29When the script encounters `CHECK EXPECTATIONS COMPLETED` (emitted by the `CHECK_EXPECTATIONS()` macro), it will assert that all previous expectations have been met. This is emitted automatically at the start of each test callback.
30
31### Test runner
32`ninja -C build test` will run `run-integration-test.py` for each test defined in `test/meson.build`. This script:
33- Creates a temporary directory in `/tmp` to serve as `XDG_RUNTIME_DIR` (this allows tests to run in parallel without interfering with each other)
34- Spins up a mock Wayland server
35- Runs the given integration test within it
36- (Both are run with `WAYLAND_DEBUG=1` so protocol messages are written to stderr by libwayland)
37- Ensures both the client and server exit successfully
38- Parses the client's protocol message expectations
39- Ensures they match the protocol messages generated by libwayland
40
41### Mock server
42Rather than running the integration tests in an external Wayland compositor, we implement our own mock Wayland compositor (located in `mock-server`). This doesn't show anything on-screen or get real user input, it simply gives the required responses to protocol messages. It's only dependency is libwayland. It implements most of the protocol with a single default dispatcher. This reads the message signature and takes whatever action appears to be required. The behavior of some messages is overridden in `overrides.c`.
43