1
0
Fork 0
mutter-performance-source/meson.build
Florian Müllner f8a257e104 Bump version to 46.beta
Update NEWS.
2024-02-11 15:51:16 +01:00

743 lines
22 KiB
Meson

project('mutter', 'c',
version: '46.beta',
meson_version: '>= 0.60.0',
license: 'GPLv2+'
)
split_version = meson.project_version().split('.')
# API version, bump each development cycle
libmutter_api_version = '14'
mutter_srcdir = meson.current_source_dir()
mutter_builddir = meson.current_build_dir()
# generic version requirements
lcms2_req = '>= 2.6'
colord_req = '>= 1.4.5'
fribidi_req = '>= 1.0.0'
glib_req = '>= 2.75.1'
gi_req = '>= 0.9.5'
graphene_req = '>= 1.10.2'
gtk3_req = '>= 3.19.8'
gtk4_req = '>= 4.0.0'
gdk_pixbuf_req = '>= 2.0'
pango_req = '>= 1.46.0'
cairo_req = '>= 1.10.0'
pangocairo_req = '>= 1.20'
pixman_req = '>= 0.42'
gsettings_desktop_schemas_req = '>= 40.alpha'
x11_req = '>= 1.7.0'
xcomposite_req = '>= 0.4'
xkbcommon_req = '>= 0.4.3'
xfixes_req = '>= 6'
xi_req = '>= 1.7.4'
xrandr_req = '>= 1.5.0'
libstartup_notification_req = '>= 0.7'
libcanberra_req = '>= 0.26'
libwacom_req = '>= 0.13'
atk_req = '>= 2.5.3'
harfbuzz_req = '>= 2.6'
libei_req = '>= 1.0.901'
# optional version requirements
udev_req = '>= 228'
gudev_req = '>= 232'
# wayland version requirements
wayland_server_req = '>= 1.21'
wayland_protocols_req = '>= 1.33'
# native backend version requirements
libinput_req = '>= 1.19.0'
gbm_req = '>= 21.3'
libdrm_req = '>= 2.4.95'
# screen cast version requirements
libpipewire_req = '>= 0.3.33'
# profiler requirements
sysprof_req = '>= 3.37.2'
gnome = import('gnome')
pkg = import('pkgconfig')
i18n = import('i18n')
fs = import('fs')
cc = meson.get_compiler('c')
add_project_link_arguments(
cc.get_supported_link_arguments(
# meson automatically adds -rpath to targets and strips them when they
# are installed. ld adds a RUNPATH tag for -rpath arguments by default.
# This makes ld add a RPATH tag instead (as it did some time ago).
# The reason why we want RPATH and not RUNPATH is that LD_LIBRARY_PATH
# takes precedence over RUNPATH but not over RPATH. Since we usually run
# development builds in jhbuild which sets up LD_LIBRARY_PATH this can
# result in wrong dependencies being picked up by the linker.
'-Wl,--disable-new-dtags',
),
language : 'c',
)
prefix = get_option('prefix')
bindir = prefix / get_option('bindir')
datadir = prefix / get_option('datadir')
libdir = prefix / get_option('libdir')
libexecdir = prefix / get_option('libexecdir')
includedir = prefix / get_option('includedir')
sysconfdir = get_option('sysconfdir')
pkgname = '@0@-@1@'.format(meson.project_name(), libmutter_api_version)
pkgdatadir = datadir / pkgname
pkglibdir = libdir / pkgname
pkgincludedir = includedir / pkgname
pcdir = libdir / 'pkgconfig'
gettext_package = meson.project_name()
localedir = datadir / 'locale'
libmutter_name = 'mutter-' + libmutter_api_version
mutter_installed_tests_datadir = datadir / 'installed-tests' / libmutter_name
mutter_installed_tests_libexecdir = libexecdir / 'installed-tests' / libmutter_name
m_dep = cc.find_library('m', required: true)
graphene_dep = dependency('graphene-gobject-1.0', version: graphene_req)
gdk_pixbuf_dep = dependency('gdk-pixbuf-2.0', version: gdk_pixbuf_req)
pango_dep = dependency('pango', version: pango_req)
cairo_dep = dependency('cairo', version: cairo_req)
pangocairo_dep = dependency('pangocairo', version: pangocairo_req)
pixman_dep = dependency('pixman-1', version: pixman_req)
fribidi_dep = dependency('fribidi', version: fribidi_req)
gsettings_desktop_schemas_dep = dependency('gsettings-desktop-schemas',
version: gsettings_desktop_schemas_req)
glib_dep = dependency('glib-2.0', version: glib_req)
gio_dep = dependency('gio-unix-2.0', version: glib_req)
gio_unix_dep = dependency('gio-unix-2.0', version: glib_req)
gobject_dep = dependency('gobject-2.0', version: glib_req)
gthread_dep = dependency('gobject-2.0', version: glib_req)
gmodule_no_export_dep = dependency('gmodule-no-export-2.0', version: glib_req)
gnome_settings_daemon_dep = dependency('gnome-settings-daemon', required: false)
xkbcommon_dep = dependency('xkbcommon', version: xkbcommon_req)
ice_dep = dependency('ice')
atk_dep = dependency('atk', version: atk_req)
dbus_dep = dependency('dbus-1')
colord_dep = dependency('colord', version: colord_req)
lcms2_dep = dependency('lcms2', version: lcms2_req)
harfbuzz_dep = dependency('harfbuzz', version: harfbuzz_req)
libeis_dep = dependency('libeis-1.0', version: libei_req)
libei_dep = dependency('libei-1.0', version: libei_req)
have_wayland = get_option('wayland')
# For now always require X11 support
have_x11 = true
have_xwayland = get_option('xwayland')
have_x11_client = have_x11 or have_xwayland
if have_xwayland and not have_wayland
error('XWayland support requires Wayland support enabled')
endif
if not have_wayland and not have_x11
error('A Wayland/X11 backend must be enabled')
endif
if have_x11_client
gtk4_dep = dependency('gtk4', version: gtk4_req)
x11_dep = dependency('x11', version: x11_req)
xcomposite_dep = dependency('xcomposite', version: xcomposite_req)
xcursor_dep = dependency('xcursor')
xdamage_dep = dependency('xdamage')
xext_dep = dependency('xext')
xfixes_dep = dependency('xfixes', version: xfixes_req)
xi_dep = dependency('xi', version: xi_req)
xtst_dep = dependency('xtst')
xkbfile_dep = dependency('xkbfile')
xkeyboard_config_dep = dependency('xkeyboard-config')
xkbcommon_x11_dep = dependency('xkbcommon-x11')
xrender_dep = dependency('xrender')
x11_xcb_dep = dependency('x11-xcb')
xrandr_dep = dependency('xrandr', version: xrandr_req)
xcb_randr_dep = dependency('xcb-randr')
xcb_res_dep = dependency('xcb-res')
xinerama_dep = dependency('xinerama')
xau_dep = dependency('xau')
endif
have_libdisplay_info = get_option('libdisplay_info')
if have_libdisplay_info
libdisplay_info_dep = dependency('libdisplay-info')
endif
have_gnome_desktop = get_option('libgnome_desktop')
if have_gnome_desktop
gnome_desktop_dep = dependency('gnome-desktop-4')
endif
have_sound_player = get_option('sound_player')
if have_sound_player
libcanberra_dep = dependency('libcanberra', version: libcanberra_req)
endif
have_gl = get_option('opengl')
if have_gl
gl_dep = dependency('gl')
gl_libname = get_option('opengl_libname')
endif
have_egl = get_option('egl')
if have_egl
egl_dep = dependency('egl')
endif
have_glx = get_option('glx') and have_x11_client
if have_glx
if not have_gl
error('GLX support requires OpenGL to be enabled')
endif
endif
have_egl_xlib = have_egl and have_x11_client
have_gles2 = get_option('gles2')
if have_gles2
gles2_dep = dependency('glesv2')
gles2_libname = get_option('gles2_libname')
if not have_egl
error('GLESv2 support requires EGL to be enabled')
endif
endif
if not have_gl and not have_gles2
error('Neither GLES2 or OpenGL was enabled')
endif
if have_wayland
wayland_server_dep = dependency('wayland-server', version: wayland_server_req)
wayland_client_dep = dependency('wayland-client', version: wayland_server_req)
wayland_cursor_dep = dependency('wayland-cursor')
wayland_protocols_dep = dependency('wayland-protocols',
version: wayland_protocols_req)
wayland_egl_dep = dependency('wayland-egl')
if not have_egl
error('Wayland support requires EGL to be enabled')
endif
endif
have_libgudev = get_option('udev')
if have_libgudev
libudev_dep = dependency('libudev', version: udev_req)
gudev_dep = dependency('gudev-1.0', version: gudev_req)
udev_dep = dependency('udev')
udev_dir = get_option('udev_dir')
if udev_dir == ''
udev_dir = udev_dep.get_variable('udevdir')
endif
endif
have_libsystemd = get_option('systemd')
libsystemd_dep = dependency('libsystemd', required: have_libsystemd)
have_native_backend = get_option('native_backend')
if have_native_backend
libgbm_dep = dependency('gbm', version: gbm_req)
libinput_dep = dependency('libinput', version: libinput_req)
if libsystemd_dep.found()
logind_provider_dep = libsystemd_dep
else
logind_provider_dep = dependency('libelogind')
endif
if not have_egl
error('The native backend requires EGL to be enabled')
endif
if not have_gles2
error('The native backend requires GLESv2 to be enabled')
endif
if not have_libgudev
error('The native backend requires udev to be enabled')
endif
endif
if have_wayland or have_native_backend
libdrm_dep = dependency('libdrm', version: libdrm_req)
endif
have_egl_device = get_option('egl_device')
have_wayland_eglstream = get_option('wayland_eglstream')
if have_wayland_eglstream
wayland_eglstream_protocols_dep = dependency('wayland-eglstream-protocols')
dl_dep = cc.find_library('dl', required: true)
if not have_wayland
error('Wayland EGLStream support requires Wayland to be enabled')
endif
endif
have_sm = get_option('sm')
if have_sm
sm_dep = dependency('sm')
endif
have_libwacom = get_option('libwacom')
if have_libwacom
libwacom_dep = dependency('libwacom', version: libwacom_req)
endif
have_pango_ft2 = get_option('pango_ft2')
if have_pango_ft2
pangoft2_dep = dependency('pangoft2')
endif
have_startup_notification = get_option('startup_notification')
if have_startup_notification
if have_x11_client
libstartup_notification_dep = dependency('libstartup-notification-1.0',
version: libstartup_notification_req)
else
error('startup_notification requires X11 or Xwayland to be enabled')
endif
endif
have_remote_desktop = get_option('remote_desktop')
if have_remote_desktop
libpipewire_dep = dependency('libpipewire-0.3', version: libpipewire_req)
endif
have_introspection = get_option('introspection')
if have_introspection
gobject_introspection_dep = dependency('gobject-introspection-1.0', version: gi_req)
introspection_args = [
'--quiet',
'-U_GNU_SOURCE',
]
introspection_common = {
'install_dir_gir': pkglibdir,
'install_dir_typelib': pkglibdir,
'install': true,
'fatal_warnings': get_option('werror'),
}
endif
have_documentation = get_option('docs')
have_tests = get_option('tests')
have_core_tests = false
have_cogl_tests = false
have_clutter_tests = false
have_native_tests = false
have_kvm_tests = false
have_tty_tests = false
have_installed_tests = false
if have_tests
gtk3_dep = dependency('gtk+-3.0', version: gtk3_req)
have_core_tests = get_option('core_tests')
if have_core_tests
if not have_wayland
error('Tests require Wayland to be enabled')
endif
if not have_x11_client
error('Tests requires an X11 client')
endif
endif
have_native_tests = get_option('native_tests')
if have_native_tests
if not have_native_backend
error('Native tests require the native backend')
endif
if not have_remote_desktop
error('Native tests require remote desktop')
endif
endif
have_kvm_tests = get_option('kvm_tests')
if have_kvm_tests
if not have_native_backend
error('KVM tests need the native backend tests')
endif
if host_machine.cpu_family() != 'x86_64'
error('KVM tests are only supported on x86_64')
endif
endif
have_tty_tests = get_option('tty_tests')
if have_tty_tests
if not have_native_backend
error('TTY tests need the native backend tests')
endif
endif
have_cogl_tests = get_option('cogl_tests')
have_clutter_tests = get_option('clutter_tests')
have_installed_tests = get_option('installed_tests')
meta_dbus_runner = find_program('src/tests/meta-dbus-runner.py')
default_test_wrappers = [
meta_dbus_runner,
'--',
]
if get_option('catch')
catch = find_program('catch')
default_test_wrappers += [
catch,
]
endif
add_test_setup('default',
is_default: true,
exe_wrapper: default_test_wrappers,
)
add_test_setup('plain')
xvfb = find_program('xvfb-run')
xvfb_args = [
'-a',
'-s',
'+iglx -noreset',
]
xvfb_command = [xvfb] + xvfb_args
add_test_setup('CI',
env: [
'MUTTER_DEBUG_DUMMY_MODE_SPECS=800x600@10.0',
],
exe_wrapper: [
default_test_wrappers,
xvfb_command,
],
timeout_multiplier: 10,
)
endif
have_profiler = get_option('profiler')
if have_profiler
# libsysprof-capture support
libsysprof_capture_dep = dependency('sysprof-capture-4',
required: true,
default_options: [
'examples=false',
'gtk=false',
'tests=false',
'tools=false',
'libsysprof=false',
'sysprofd=none',
'help=false',
],
fallback: ['sysprof', 'libsysprof_capture_dep'],
version: sysprof_req,
)
if libsysprof_capture_dep.type_name() == 'pkgconfig'
sysprof_dep = dependency('sysprof-6', 'sysprof-4')
sysprof_dbus_interfaces_dir = sysprof_dep.get_variable('datadir') / 'dbus-1' / 'interfaces'
else
sysprof_dbus_interfaces_dir = mutter_srcdir / 'subprojects' / 'sysprof' / 'src'
endif
endif
required_functions = [
'ffs',
'clz',
'memmem',
]
foreach function : required_functions
if not cc.has_function(function)
error('Required function ' + function + ' missing')
endif
endforeach
if host_machine.cpu_family() == 'x86'
add_project_arguments('-ffloat-store', language: 'c')
endif
add_project_arguments('-D_GNU_SOURCE', language: 'c')
buildtype = get_option('buildtype')
if buildtype != 'plain'
mutter_c_args = [
'-fno-omit-frame-pointer',
'-mno-omit-leaf-frame-pointer',
'-fno-strict-aliasing',
'-Wpointer-arith',
'-Wmissing-declarations',
'-Wformat=2',
'-Wstrict-prototypes',
'-Wmissing-prototypes',
'-Wnested-externs',
'-Wold-style-definition',
'-Wundef',
'-Wunused',
'-Wcast-align',
'-Wmissing-noreturn',
'-Wmissing-format-attribute',
'-Wmissing-include-dirs',
'-Wlogical-op',
'-Wignored-qualifiers',
'-Werror=redundant-decls',
'-Werror=implicit',
'-Werror=nonnull',
'-Werror=init-self',
'-Werror=main',
'-Werror=missing-braces',
'-Werror=sequence-point',
'-Werror=return-type',
'-Werror=trigraphs',
'-Werror=array-bounds',
'-Werror=write-strings',
'-Werror=address',
'-Werror=int-to-pointer-cast',
'-Werror=pointer-to-int-cast',
'-Werror=empty-body',
'-Werror=write-strings',
'-Werror=strict-aliasing',
'-Wno-sign-compare',
'-Wno-cast-function-type',
'-Wno-unused-parameter',
'-Wno-missing-field-initializers',
'-Wno-type-limits',
]
if get_option('debug')
mutter_c_args += [
'-DG_ENABLE_DEBUG',
]
endif
supported_mutter_c_args = cc.get_supported_arguments(mutter_c_args)
add_project_arguments(supported_mutter_c_args, language: 'c')
endif
cc.compiles('void main (void) { __builtin_ffsl (0); __builtin_popcountl (0); }')
cdata = configuration_data()
cdata.set_quoted('GETTEXT_PACKAGE', gettext_package)
cdata.set_quoted('VERSION', meson.project_version())
cdata.set_quoted('PACKAGE_NAME', meson.project_name())
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
cdata.set('HAVE_EGL', have_egl)
cdata.set('HAVE_GLX', have_glx)
cdata.set('HAVE_EGL_PLATFORM_XLIB', have_egl_xlib)
cdata.set('HAVE_GL', have_gl)
cdata.set('HAVE_GLES2', have_gles2)
cdata.set('HAVE_WAYLAND', have_wayland)
cdata.set('HAVE_XWAYLAND', have_xwayland)
cdata.set('HAVE_X11', have_x11)
cdata.set('HAVE_X11_CLIENT', have_x11_client)
cdata.set('HAVE_LIBSYSTEMD', have_libsystemd)
cdata.set('HAVE_NATIVE_BACKEND', have_native_backend)
cdata.set('HAVE_REMOTE_DESKTOP', have_remote_desktop)
cdata.set('HAVE_GNOME_DESKTOP', have_gnome_desktop)
cdata.set('HAVE_SOUND_PLAYER', have_sound_player)
cdata.set('HAVE_EGL_DEVICE', have_egl_device)
cdata.set('HAVE_WAYLAND_EGLSTREAM', have_wayland_eglstream)
cdata.set('HAVE_LIBGUDEV', have_libgudev)
cdata.set('HAVE_LIBWACOM', have_libwacom)
cdata.set('HAVE_SM', have_sm)
cdata.set('HAVE_STARTUP_NOTIFICATION', have_startup_notification)
cdata.set('HAVE_INTROSPECTION', have_introspection)
cdata.set('HAVE_PROFILER', have_profiler)
cdata.set('HAVE_LIBDISPLAY_INFO', have_libdisplay_info)
cdata.set('HAVE_PANGO_FT2', have_pango_ft2)
if have_x11_client
xkb_base = xkeyboard_config_dep.get_variable('xkb_base')
cdata.set_quoted('XKB_BASE', xkb_base)
endif
if cc.has_header_symbol('sys/prctl.h', 'prctl')
cdata.set('HAVE_SYS_PRCTL', 1)
endif
have_xwayland_initfd = false
have_xwayland_listenfd = false
have_xwayland_terminate_delay = false
have_xwayland_byte_swapped_clients = false
have_xwayland_enable_ei_portal = false
if have_xwayland
xwayland_dep = dependency('xwayland', required: false)
xwayland_path = get_option('xwayland_path')
if xwayland_path == ''
if xwayland_dep.found()
xwayland_path = xwayland_dep.get_variable('xwayland')
else
xwayland_path = find_program('Xwayland').path()
endif
endif
cdata.set_quoted('XWAYLAND_PATH', xwayland_path)
# For Xwayland authority file generation.
if cc.has_header_symbol('sys/random.h', 'getrandom')
cdata.set('HAVE_SYS_RANDOM', 1)
elif cc.has_header_symbol('linux/random.h', 'getrandom')
cdata.set('HAVE_LINUX_RANDOM', 1)
else
error('Required function getrandom not found')
endif
# For Xwayland -initfd usage
use_initfd = get_option('xwayland_initfd')
if xwayland_dep.found()
xwayland_supports_initfd = xwayland_dep.get_variable('have_initfd') == 'true'
else
xwayland_options = run_command(xwayland_path, '-help')
xwayland_supports_initfd = xwayland_options.stderr().contains('-initfd')
endif
if use_initfd.auto()
have_xwayland_initfd = xwayland_supports_initfd
else
have_xwayland_initfd = use_initfd.enabled()
if have_xwayland_initfd and not xwayland_supports_initfd
error('XWayland -initfd support requested but not available')
endif
endif
if (have_xwayland_initfd)
cdata.set('HAVE_XWAYLAND_INITFD', 1)
endif
# For Xwayland -listenfd usage
if xwayland_dep.found()
have_xwayland_listenfd = xwayland_dep.get_variable('have_listenfd') == 'true'
endif
if (have_xwayland_listenfd)
cdata.set('HAVE_XWAYLAND_LISTENFD', 1)
endif
# For Xwayland -listenfd usage
if xwayland_dep.found()
have_xwayland_terminate_delay = xwayland_dep.get_variable('have_terminate_delay') == 'true'
endif
if (have_xwayland_terminate_delay)
cdata.set('HAVE_XWAYLAND_TERMINATE_DELAY', 1)
endif
# For Xwayland +/-byteswappedclients usage
if xwayland_dep.found()
have_xwayland_byte_swapped_clients = xwayland_dep.get_variable('have_byteswappedclients',
default_value: 'false') == 'true'
endif
if (have_xwayland_byte_swapped_clients)
cdata.set('HAVE_XWAYLAND_BYTE_SWAPPED_CLIENTS', 1)
endif
# For Xwayland -enable-portal usage
if xwayland_dep.found()
have_xwayland_enable_ei_portal = xwayland_dep.get_variable('have_enable_ei_portal',
default_value: 'false') == 'true'
endif
if (have_xwayland_enable_ei_portal)
cdata.set('HAVE_XWAYLAND_ENABLE_EI_PORTAL', 1)
endif
endif
optional_functions = [
'mkostemp',
'posix_fallocate',
'memfd_create',
]
foreach function : optional_functions
if cc.has_function(function)
cdata.set('HAVE_' + function.to_upper(), 1)
else
message('Optional function ' + function + ' missing')
endif
endforeach
xwayland_grab_default_access_rules = get_option('xwayland_grab_default_access_rules')
cdata.set_quoted('XWAYLAND_GRAB_DEFAULT_ACCESS_RULES',
xwayland_grab_default_access_rules)
cdata.set_quoted('MUTTER_PLUGIN_DIR', pkglibdir / 'plugins')
cdata.set_quoted('MUTTER_LOCALEDIR', localedir)
cdata.set_quoted('MUTTER_LIBEXECDIR', libexecdir)
cdata.set_quoted('MUTTER_PKGDATADIR', pkgdatadir)
config_h = configure_file(
input: 'config.h.meson',
output: 'config.h',
configuration: cdata
)
top_includepath = include_directories('.')
subdir('mtk')
subdir('cogl')
subdir('clutter')
subdir('data')
subdir('tools')
subdir('src')
subdir('po')
subdir('doc/man')
if have_documentation
subdir('doc/reference')
endif
gnome.post_install(
glib_compile_schemas: true,
)
meson.add_dist_script('meson/check-version.py', meson.project_version(), 'NEWS')
summary('prefix', prefix, section: 'Directories')
summary('libexecdir', libexecdir, section: 'Directories')
summary('pkgdatadir', pkgdatadir, section: 'Directories')
summary('buildtype', get_option('buildtype'), section: 'Build Configuration')
summary('debug', get_option('debug'), section: 'Build Configuration')
summary('OpenGL', have_gl, section: 'Rendering APIs')
summary('GLES2', have_gles2, section: 'Rendering APIs')
summary('EGL', have_egl, section: 'Rendering APIs')
summary('GLX', have_glx, section: 'Rendering APIs')
summary('Wayland', have_wayland, section: 'Options')
summary('Wayland EGLStream', have_wayland_eglstream, section: 'Options')
summary('X11', have_x11, section: 'Options')
summary('XWayland', have_xwayland, section: 'Options')
summary('Native Backend', have_native_backend, section: 'Options')
summary('EGL Device', have_egl_device, section: 'Options')
summary('Remote desktop', have_remote_desktop, section: 'Options')
summary('libgnome-desktop', have_gnome_desktop, section: 'Options')
summary('libdisplay-info', have_libdisplay_info, section: 'Options')
summary('Sound player', have_sound_player, section: 'Options')
summary('gudev', have_libgudev, section: 'Options')
summary('Wacom', have_libwacom, section: 'Options')
summary('SM', have_sm, section: 'Options')
summary('Startup notification', have_startup_notification, section: 'Options')
summary('Introspection', have_introspection, section: 'Options')
summary('Documentation', have_documentation, section: 'Options')
summary('Profiler', have_profiler, section: 'Options')
summary('Xwayland initfd', have_xwayland_initfd, section: 'Options')
summary('Xwayland listenfd', have_xwayland_listenfd, section: 'Options')
summary('Xwayland terminate delay', have_xwayland_terminate_delay, section: 'Options')
summary('Xwayland byte-swapped clients', have_xwayland_byte_swapped_clients, section: 'Options')
summary('Xwayland enable EI portal', have_xwayland_enable_ei_portal, section: 'Options')
summary('Enabled', have_tests, section: 'Tests')
summary('Core tests', have_core_tests, section: 'Tests')
summary('Cogl tests', have_cogl_tests, section: 'Tests')
summary('Clutter tests', have_clutter_tests, section: 'Tests')
summary('KVM tests', get_option('kvm_tests'), section: 'Tests')
summary('Installed tests', have_installed_tests, section: 'Tests')
summary('Coverage', get_option('b_coverage'), section: 'Tests')