This is an automated email from the git hooks/post-receive script.

git pushed a commit to reference refs/pull/145/head
in repository enlightenment.

View the commit online.

commit b5e6c906caad7b71ee84af5806de6a628780b4d3
Author: Cedric BAIL <[email protected]>
AuthorDate: Fri Aug 7 23:14:05 2026 -0600

    tests - add a -Dtests option, the check harness and a wltest profile
    
    Groundwork for an automated Wayland test suite. E has no test runner at
    all today: src/tests/ holds eight standalone X11 clients that are driven
    by hand and are not in the build.
    
    Three pieces, none of them wired to a test yet:
    
      - a 'tests' meson option, default false, gating a new src/tests build;
    
      - efl_check.h and timeout.c, copied verbatim from core/efl src/tests/.
        EFL already has a check(1) harness with EFL_START_TEST/EFL_END_TEST,
        fork-mode isolation and meson test() wiring. Same project, same
        idioms - better to reuse it than invent a second one. Prefer
        re-syncing from EFL over editing these locally;
    
      - a 'wltest' config profile, installed only with -Dtests=true.
    
    The profile needs a word of explanation. The default profile enables
    exactly one module, wizard, and expects the wizard to set up everything
    else on first run. That is wrong twice over for a test: the wizard opens
    a window and waits for input, and wl_desktop_shell is never loaded, so
    xdg_wm_base is not advertised and there is almost nothing left to test.
    wltest is the default profile with that one module swapped.
    
    Keep the module list there minimal and explicit. A test that needs
    another module should say so, rather than the suite quietly depending on
    whatever the default profile happens to enable this release.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
    Claude-Session: https://claude.ai/code/session_01FtoiXoSKUmZb6Aix6U3GZS
---
 data/config/meson.build           |   6 +
 data/config/wltest/e.src          | 248 +++++++++++++++++++
 data/config/wltest/e_bindings.src | 257 +++++++++++++++++++
 data/config/wltest/meson.build    |  19 ++
 meson_options.txt                 |   4 +
 src/tests/efl_check.h             | 506 ++++++++++++++++++++++++++++++++++++++
 src/tests/meson.build             |  11 +
 src/tests/timeout.c               |  17 ++
 8 files changed, 1068 insertions(+)

diff --git a/data/config/meson.build b/data/config/meson.build
index a63ded7ef..10c1868b0 100644
--- a/data/config/meson.build
+++ b/data/config/meson.build
@@ -18,3 +18,9 @@ custom_target('profile.src',
 subdir('default')
 subdir('standard')
 subdir('tiling')
+
+# Profile used by the Wayland test suite; only worth installing when the
+# tests are built.
+if get_option('tests') == true
+  subdir('wltest')
+endif
diff --git a/data/config/wltest/e.src b/data/config/wltest/e.src
new file mode 100644
index 000000000..6d5c12433
--- /dev/null
+++ b/data/config/wltest/e.src
@@ -0,0 +1,248 @@
+// Profile used by the Wayland test suite (E_CONF_PROFILE=wltest).
+//
+// A copy of the "default" profile with exactly one change: the module list
+// loads wl_desktop_shell instead of wizard. The wizard would otherwise open a
+// window and wait for input on every test run, and the default profile does
+// not load wl_desktop_shell at all -- so without this, xdg_wm_base is never
+// advertised and almost nothing is testable.
+//
+// Keep this list minimal and explicit. A test that needs another module
+// should say so, rather than the suite quietly depending on whatever the
+// default profile happens to enable this release.
+group "E_Config" struct {
+  value "config_version" int: 1000035;
+  value "config_type" uint: 0; // this profile seems to just be super minimalist
+  value "desktop_default_name" string: "%i-%i";
+  value "desktop_default_window_profile" string: "";
+  value "menus_scroll_speed" double: 1000.0;
+  value "menus_fast_mouse_move_threshhold" double: 300.0;
+  value "menus_click_drag_timeout" double: 0.25;
+  value "border_shade_animate" int: 1;
+  value "border_shade_transition" int: 3;
+  value "border_shade_speed" double: 3000.0;
+  value "priority" int: 3;
+  value "image_cache" int: 4096;
+  value "font_cache" int: 512;
+  value "edje_cache" int: 10;
+  value "edje_collection_cache" int: 30;
+  value "zone_desks_x_count" int: 1;
+  value "zone_desks_y_count" int: 1;
+  value "show_desktop_icons" int: 1;
+  value "edge_flip_dragging" int: 0;
+  value "use_shaped_win" int: 0;
+  group "modules" list {
+    group "E_Config_Module" struct {
+      value "name" string: "wl_desktop_shell";
+      value "enabled" uchar: 1;
+    }
+  }
+  value "window_placement_policy" int: 0;
+  value "window_grouping" int: 0;
+  value "focus_policy" int: 0;
+  value "focus_setting" int: 1;
+  value "pass_click_on" int: 1;
+  value "always_click_to_raise" int: 0;
+  value "always_click_to_focus" int: 0;
+  value "use_auto_raise" int: 0;
+  value "auto_raise_delay" double: 0.5;
+  value "use_resist" int: 1;
+  value "drag_resist" int: 16;
+  value "desk_resist" int: 32;
+  value "window_resist" int: 12;
+  value "gadget_resist" int: 32;
+  value "geometry_auto_resize_limit" int: 1;
+  value "geometry_auto_move" int: 1;
+  value "winlist_warp_while_selecting" int: 0;
+  value "winlist_warp_at_end" int: 1;
+  value "pointer_warp_speed" double: 0.1;
+  value "winlist_scroll_animate" int: 1;
+  value "winlist_scroll_speed" double: 0.1;
+  value "winlist_list_show_iconified" int: 1;
+  value "winlist_list_show_other_desk_iconified" int: 1;
+  value "winlist_list_show_other_screen_iconified" int: 0;
+  value "winlist_list_show_other_desk_windows" int: 0;
+  value "winlist_list_show_other_screen_windows" int: 0;
+  value "winlist_list_uncover_while_selecting" int: 0;
+  value "winlist_list_jump_desk_while_selecting" int: 0;
+  value "winlist_list_focus_while_selecting" int: 0;
+  value "winlist_list_raise_while_selecting" int: 0;
+  value "winlist_mode" int: 1;
+  value "winlist_large_size" double: 0.6666;
+  value "winlist_list_size" double: 0.3333;
+  value "winlist_list_no_miniatures" uchar: 0;
+  value "no_state_hidden_desktop" uchar: 0;
+  value "maximize_policy" int: 49;
+  value "allow_manip" int: 0;
+  value "border_fix_on_shelf_toggle" int: 0;
+  value "allow_above_fullscreen" int: 0;
+  value "kill_if_close_not_possible" int: 1;
+  value "kill_process" int: 1;
+  value "kill_timer_wait" double: 10.0;
+  value "ping_clients" int: 1;
+  value "transition_desk" string: "vswipe";
+  value "transition_change" string: "crossfade";
+  value "remember_internal_windows" int: 0;
+  value "move_info_follows" int: 1;
+  value "resize_info_follows" int: 1;
+  value "move_info_visible" int: 1;
+  value "resize_info_visible" int: 1;
+  value "focus_last_focused_per_desktop" int: 1;
+  value "focus_revert_on_hide_or_close" int: 1;
+  value "pointer_slide" int: 0;
+  value "use_e_cursor" int: 1;
+  value "cursor_size" int: 32;
+  value "menu_autoscroll_margin" int: 0;
+  value "menu_autoscroll_cursor_margin" int: 1;
+  value "transient.move" int: 1;
+  value "transient.resize" int: 0;
+  value "transient.raise" int: 1;
+  value "transient.lower" int: 1;
+  value "transient.layer" int: 1;
+  value "transient.desktop" int: 1;
+  value "transient.iconify" int: 1;
+  value "modal_windows" int: 1;
+  value "menu_eap_name_show" int: 1;
+  value "menu_eap_generic_show" int: 1;
+  value "menu_eap_comment_show" int: 0;
+  value "menu_gadcon_client_toplevel" int: 0;
+  value "fullscreen_policy" int: 0;
+  value "exebuf_term_cmd" string: "xterm -hold -e";
+  value "use_app_icon" int: 0;
+  value "cnfmdlg_disabled" int: 0;
+  value "cfgdlg_auto_apply" int: 0;
+  value "cfgdlg_default_mode" int: 0;
+  value "font_hinting" int: 0;
+  value "desklock_background" string: "theme_desklock_background";
+  value "desklock_auth_method" int: 0;
+  value "desklock_login_box_zone" int: -1;
+  value "desklock_start_locked" int: 0;
+  value "desklock_on_suspend" int: 0;
+  value "desklock_autolock_screensaver" int: 0;
+  value "desklock_post_screensaver_time" double: 0.0;
+  value "desklock_use_custom_desklock" int: 0;
+  value "desklock_ask_presentation" uchar: 1;
+  value "desklock_ask_presentation_timeout" double: 30;
+  value "display_res_restore" int: 0;
+  value "display_res_width" int: 1;
+  value "display_res_height" int: 1;
+  value "display_res_hz" int: 0;
+  value "display_res_rotation" int: 0;
+  value "screensaver_enable" int: 0;
+  value "screensaver_timeout" int: 60;
+  value "screensaver_interval" int: 5;
+  value "screensaver_blanking" int: 2;
+  value "screensaver_expose" int: 2;
+  value "screensaver_ask_presentation" uchar: 1;
+  value "screensaver_ask_presentation_timeout" double: 30;
+  value "dpms_enable" int: 1;
+  value "dpms_standby_enable" int: 1;
+  value "dpms_suspend_enable" int: 1;
+  value "dpms_off_enable" int: 1;
+  value "dpms_standby_timeout" int: 300;
+  value "dpms_suspend_timeout" int: 300;
+  value "dpms_off_timeout" int: 300;
+  value "clientlist_group_by" int: 0;
+  value "clientlist_include_all_zones" int: 0;
+  value "clientlist_separate_with" int: 0;
+  value "clientlist_sort_by" int: 0;
+  value "clientlist_separate_iconified_apps" int: 0;
+  value "clientlist_warp_to_iconified_desktop" int: 0;
+  value "clientlist_limit_caption_len" int: 0;
+  value "clientlist_max_caption_len" int: 2;
+  value "mouse_hand" int: 1;
+  value "mouse_accel" double: 0.0;
+  value "mouse_flat_accel" uchar: 0;
+  value "mouse_hires_scroll" uchar: 1;
+  value "mouse_accel_threshold" int: 4;
+  value "mouse_natural_scroll" uchar: 0;
+  value "mouse_emulate_middle_button" uchar: 1;
+  value "touch_accel" double: 0.0;
+  value "touch_natural_scroll" uchar: 0;
+  value "touch_emulate_middle_button" uchar: 1;
+  value "touch_tap_to_click" uchar: 0;
+  value "touch_flat_accel" uchar: 0;
+  value "touch_clickpad" uchar: 1;
+  value "touch_scrolling_2finger" uchar: 1;
+  value "touch_scrolling_edge" uchar: 0;
+  value "touch_scrolling_circular" uchar: 0;
+  value "touch_scrolling_horiz" uchar: 1;
+  value "touch_palm_detect" uchar: 1;
+  value "border_raise_on_mouse_action" int: 1;
+  value "desk_flip_wrap" int: 0;
+  value "fullscreen_flip" int: 1;
+  value "icon_theme" string: "hicolor";
+  value "desk_flip_animate_mode" int: 0;
+  value "desk_flip_animate_interpolation" int: 0;
+  value "desk_flip_animate_time" double: 0.5;
+  value "wallpaper_import_last_dev" string: "/tmp";
+  value "wallpaper_import_last_path" string: "/";
+  value "theme_default_border_style" string: "default";
+  value "desk_auto_switch" int: 0;
+  value "thumb_nice" int: 0;
+  value "gesture_open_input_devices" int: 0;
+  value "screen_limits" int: 0;
+  value "menu_favorites_show" int: 1;
+  value "menu_apps_show" int: 1;
+  value "ping_clients_interval" int: 16;
+  value "cache_flush_poll_interval" int: 528;
+  value "thumbscroll_enable" int: 1;
+  value "thumbscroll_threshhold" int: 24;
+  value "thumbscroll_momentum_threshhold" double: 0.0;
+  value "thumbscroll_friction" double: 1.0;
+  value "dbus_desktop" int: 1;
+  value "border_keyboard.timeout" double: 5.0;
+  value "border_keyboard.move.dx" uchar: 5;
+  value "border_keyboard.move.dy" uchar: 5;
+  value "border_keyboard.resize.dx" uchar: 5;
+  value "border_keyboard.resize.dy" uchar: 5;
+  value "dbus_desktop" int: 1;
+  value "scale.min" double: 0.8;
+  value "scale.max" double: 5.0;
+  value "scale.factor" double: 1.0;
+  value "scale.base_dpi" int: 90;
+  value "scale.use_dpi" uchar: 1;
+  value "scale.use_custom" uchar: 0;
+  value "scale.xapp_base_dpi" int: 75;
+  value "scale.set_xapp_dpi" uchar: 1;
+  value "show_cursor" uchar: 1;
+  value "idle_cursor" uchar: 1;
+  value "default_system_menu" string: "";
+  value "cfgdlg_normal_wins" uchar: 0;
+  value "syscon.main.icon_size" int: 64;
+  value "syscon.secondary.icon_size" int: 48;
+  value "syscon.extra.icon_size" int: 48;
+  value "syscon.timeout" double: 0.0;
+  value "syscon.do_input" uchar: 0;
+  value "exec.expire_timeout" double: 30.0;
+  value "exec.show_run_dialog" uchar: 1;
+  value "exec.show_exit_dialog" uchar: 1;
+  value "null_container_win" uchar: 1;
+  value "backlight.normal" double: 1.0;
+  value "backlight.dim" double: 0.3;
+  value "backlight.transition" double: 0.5;
+  value "backlight.timer" double: 30.0;
+  value "backlight.battery_timer" double: 20.0;
+  value "backlight.idle_dim" uchar: 1;
+  value "backlight.ddc" uchar: 0;
+  value "device_desktop" int: 0;
+  value "device_auto_mount" int: 0;
+  value "device_auto_open" int: 0;
+  value "xsettings.match_e17_theme" uchar: 1;
+  value "xsettings.match_e17_icon_theme" uchar: 1;
+  value "update.check" uchar: 0;
+  value "update.later" uchar: 0;
+  value "xkb.only_label" int: 0;
+  value "xkb.default_model" string: "default";
+  value "xkb.use_cache" uchar: 0;
+  value "keyboard.repeat_delay" int: 400;
+  value "keyboard.repeat_rate" int: 25;
+  value "exe_always_single_instance" uchar: 0;
+  value "use_desktop_window_profile" int: 0;
+  value "powersave.none" double: 0.25;
+  value "powersave.low" double: 5.0;
+  value "powersave.medium" double: 60.0;
+  value "powersave.high" double: 300.0;
+  value "powersave.extreme" double: 1200.0;
+  value "powersave.min" int: 0;
+  value "powersave.max" int: 5;
+}
diff --git a/data/config/wltest/e_bindings.src b/data/config/wltest/e_bindings.src
new file mode 100644
index 000000000..0f11f7e11
--- /dev/null
+++ b/data/config/wltest/e_bindings.src
@@ -0,0 +1,257 @@
+group "E_Config_Bindings" struct {
+  value "config_version" int: 0;
+  group "mouse_bindings" list {
+    group "E_Config_Binding_Mouse" struct {
+      value "context" int: 3;
+      value "modifiers" int: 0;
+      value "action" string: "menu_show";
+      value "params" string: "main";
+      value "button" uchar: 1;
+      value "any_mod" uchar: 0;
+    }
+  }
+  group "signal_bindings" list {
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1,double";
+      value "source" string: "e.event.titlebar";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_shaded_toggle";
+      value "params" string: "up";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,2";
+      value "source" string: "e.event.titlebar";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_shaded_toggle";
+      value "params" string: "up";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,wheel,?,1";
+      value "source" string: "e.event.titlebar";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_shaded";
+      value "params" string: "0 up";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,wheel,?,-1";
+      value "source" string: "e.event.titlebar";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_shaded";
+      value "params" string: "1 up";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,clicked,3";
+      value "source" string: "e.event.titlebar";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_menu";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,clicked,?";
+      value "source" string: "e.event.icon";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_menu";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,clicked,[12]";
+      value "source" string: "e.event.close";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_close";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,clicked,3";
+      value "source" string: "e.event.close";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_kill";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,clicked,1";
+      value "source" string: "e.event.maximize";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_maximized_toggle";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,clicked,2";
+      value "source" string: "e.event.maximize";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_maximized_toggle";
+      value "params" string: "smart";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,clicked,3";
+      value "source" string: "e.event.maximize";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_maximized_toggle";
+      value "params" string: "expand";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,clicked,?";
+      value "source" string: "e.event.minimize";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_iconic_toggle";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,clicked,?";
+      value "source" string: "e.event.shade";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_shaded_toggle";
+      value "params" string: "up";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,clicked,?";
+      value "source" string: "e.event.lower";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_lower";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1";
+      value "source" string: "e.event.icon";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_drag_icon";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1";
+      value "source" string: "e.event.titlebar";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_move";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,up,1";
+      value "source" string: "e.event.titlebar";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_move";
+      value "params" string: "end";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1";
+      value "source" string: "e.event.resize.tl";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_resize";
+      value "params" string: "tl";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1";
+      value "source" string: "e.event.resize.t";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_resize";
+      value "params" string: "t";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1";
+      value "source" string: "e.event.resize.tr";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_resize";
+      value "params" string: "tr";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1";
+      value "source" string: "e.event.resize.r";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_resize";
+      value "params" string: "r";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1";
+      value "source" string: "e.event.resize.br";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_resize";
+      value "params" string: "br";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1";
+      value "source" string: "e.event.resize.b";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_resize";
+      value "params" string: "b";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1";
+      value "source" string: "e.event.resize.bl";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_resize";
+      value "params" string: "bl";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,1";
+      value "source" string: "e.event.resize.l";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_resize";
+      value "params" string: "l";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,up,1";
+      value "source" string: "e.event.resize.*";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_resize";
+      value "params" string: "end";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,down,3";
+      value "source" string: "e.event.resize.*";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_move";
+    }
+    group "E_Config_Binding_Signal" struct {
+      value "context" int: 2;
+      value "signal" string: "mouse,up,3";
+      value "source" string: "e.event.resize.*";
+      value "modifiers" int: 0;
+      value "any_mod" uchar: 1;
+      value "action" string: "window_move";
+      value "params" string: "end";
+    }
+  }
+}
diff --git a/data/config/wltest/meson.build b/data/config/wltest/meson.build
new file mode 100644
index 000000000..ce49a7e84
--- /dev/null
+++ b/data/config/wltest/meson.build
@@ -0,0 +1,19 @@
+dir = 'wltest'
+src = [
+  'e',
+  'e_bindings'
+]
+
+##### boilerplate config build + install of icons/dirs
+i = 0
+foreach cd: src
+  custom_target(' '.join(['config_dist', dir, cd]),
+		input        : cd + '.src',
+		output       : cd + '.cfg',
+		command      : [eet_cmd, '-e', '@OUTPUT@', 'config', '@INPUT@', '1'],
+		install      : true,
+		install_dir  : join_paths(dir_config, dir),
+                install_mode : 'rw-r--r--'
+               )
+  i += 1
+endforeach
diff --git a/meson_options.txt b/meson_options.txt
index 70b30bb30..6e81f6551 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -330,3 +330,7 @@ option('clipboard',
 	type: 'boolean',
 	value: true,
 	description: 'enable clipboard module: (default=true)')
+option('tests',
+	type: 'boolean',
+	value: false,
+	description: 'build the test suites: (default=false)')
diff --git a/src/tests/efl_check.h b/src/tests/efl_check.h
new file mode 100644
index 000000000..ef2c68399
--- /dev/null
+++ b/src/tests/efl_check.h
@@ -0,0 +1,506 @@
+/* Test harness macros and check(1) suite runner.
+ *
+ * Copied verbatim from core/efl src/tests/efl_check.h so that E's Wayland
+ * test suite uses the same idioms as EFL's. Keep changes here to a minimum
+ * and prefer re-syncing from EFL over local edits.
+ */
+#ifndef EFL_CHECK_H
+#define EFL_CHECK_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h> /* getenv */
+#include <stdio.h> /* fprintf, fputs */
+#include <string.h> /* strcmp */
+#include <unistd.h> /* execvp */
+#include <errno.h> /* errno */
+#include <sys/time.h>
+
+#ifdef HAVE_FORK
+# ifdef HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+# endif
+# ifdef HAVE_SYS_WAIT_H
+#  include <sys/wait.h>
+# endif
+# include <signal.h>
+#endif
+
+#include <Eina.h>
+
+#ifndef EINA_UNUSED
+
+# ifdef __GNUC__
+
+#  if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#   define EINA_UNUSED __attribute__ ((__unused__))
+#  else
+#   define EINA_UNUSED
+#  endif
+# else
+#  define EINA_UNUSED
+# endif
+
+#endif
+
+#ifdef HAVE_GETTIMEOFDAY
+# if CHECK_MINOR_VERSION >= 11
+#  define ENABLE_TIMING_INFO
+# endif
+#endif
+
+/* Uncomment this line to print a warning line to stdout for every expected error received.
+   Otherwise, expected errors are just silently ignored, greatly reducing the log size.
+*/
+//#define PRINT_EXPECTED_ERROR
+
+#define DISABLE_ABORT_ON_CRITICAL_START \
+   do { \
+      int ___val = eina_log_abort_on_critical_get(); \
+      eina_log_abort_on_critical_set(0)
+
+#define DISABLE_ABORT_ON_CRITICAL_END \
+      eina_log_abort_on_critical_set(___val); \
+   } while (0)
+
+#define EXPECT_ERROR_START \
+  do { \
+      DISABLE_ABORT_ON_CRITICAL_START; \
+      Eina_Bool expect_error_start = EINA_FALSE; \
+      do { \
+        eina_log_print_cb_set(_efl_test_expect_error, &expect_error_start); \
+      } while(0)
+
+
+#define EXPECT_ERROR_END \
+    eina_log_print_cb_set(NULL, NULL); \
+    ck_assert_int_eq(expect_error_start, EINA_TRUE); \
+    DISABLE_ABORT_ON_CRITICAL_END; \
+  } while(0)
+
+typedef struct _Efl_Test_Case Efl_Test_Case;
+struct _Efl_Test_Case
+{
+   const char *test_case;
+   void (*build)(TCase *tc);
+};
+
+#ifdef HAVE_FORK
+static int timeout_pid = 0;
+#endif
+
+EINA_UNUSED static void
+_efl_test_expect_error(const Eina_Log_Domain *d EINA_UNUSED, Eina_Log_Level level, const char *file EINA_UNUSED, const char *fnc, int line EINA_UNUSED, const char *fmt EINA_UNUSED, void *data, va_list args EINA_UNUSED)
+{
+   Eina_Bool *error = (Eina_Bool*) data;
+   if (level == EINA_LOG_LEVEL_ERR) *error = EINA_TRUE;
+#ifdef PRINT_EXPECTED_ERROR
+   printf("EXPECTED ERROR %s\n", fnc);
+#else
+   (void)fnc;
+#endif
+}
+
+static void
+_efl_tests_list(const Efl_Test_Case *etc)
+{
+   const Efl_Test_Case *itr = etc;
+      fputs("Available Test Cases:\n", stderr);
+   for (; itr->test_case; itr++)
+      fprintf(stderr, "\t%s\n", itr->test_case);
+}
+
+EINA_UNUSED static int
+_efl_test_option_disp(int argc, char **argv, const Efl_Test_Case *etc)
+{
+   int i;
+
+   for (i = 1; i < argc; i++)
+     {
+        if ((strcmp(argv[i], "-h") == 0) ||
+            (strcmp(argv[i], "--help") == 0))
+          {
+             fprintf(stderr, "Usage: %s [options] [test_case1 .. [test_caseN]]\n",
+                     argv[0]);
+             fprintf(stderr, " -l\t--list\t\tList all tests case.\n");
+             fprintf(stderr, " \t--valgrind\tRun the tests under valgrind.\n");
+             fprintf(stderr, "\nNote that CK_RUN_CASE=test_case does also filter which tests are run\n");
+             return 0;
+          }
+        else if ((strcmp(argv[i], "-l") == 0) ||
+                 (strcmp(argv[i], "--list") == 0))
+          {
+             _efl_tests_list(etc);
+             return 0;
+          }
+        else if (strcmp(argv[i], "--valgrind") == 0)
+          {
+             const char ** nav = (const char **) alloca(sizeof(char*) * (argc + 3));
+             int j, k;
+
+             nav[0] = "valgrind";
+             nav[1] = "--trace-children=yes";
+             for (j = 0, k = 2; j < argc; j++)
+               {
+                  if (i == j) continue ; // Remove --valgrind
+                  nav[k++] = argv[j];
+               }
+
+             nav[k] = NULL;
+             execvp("valgrind", (char**) nav);
+             fprintf(stderr, "Failed to execute valgrind due to '%s'\n", strerror(errno));
+             return 0;
+          }
+     }
+
+   return 1;
+}
+
+static int
+_efl_test_use(int argc, const char **argv, const char *test_case)
+{
+   if (argc < 1)
+     return 1;
+
+   for (; argc > 0; argc--, argv++)
+     if (strcasecmp(test_case, *argv) == 0)
+       return 1;
+   return 0;
+}
+
+#ifdef HAVE_FORK
+static int
+_efl_test_fork_has(SRunner *sr)
+{
+   if (srunner_fork_status(sr) == CK_FORK)
+     return 1;
+   else if (srunner_fork_status(sr) == CK_NOFORK)
+     return 0;
+   else if (srunner_fork_status(sr) == CK_FORK_GETENV)
+     {
+        char *res;
+
+        res = getenv("CK_FORK");
+        if (res && (strcmp(res, "no") == 0))
+          return 0;
+        else
+          return 1;
+     }
+
+   /* should never get there */
+   return 0;
+}
+#endif
+
+#ifdef ENABLE_TIMING_INFO
+EINA_UNUSED static double _timing_start_time;
+
+static int
+_timing_enabled(void)
+{
+   const char *lc = getenv("TIMING_ENABLED");
+   return !!lc;
+}
+
+static double
+_timing_time_get(void)
+{
+   struct timeval timev;
+
+   gettimeofday(&timev, NULL);
+   return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
+}
+
+EINA_UNUSED static void
+_timing_start(void)
+{
+   if (_timing_enabled())
+     _timing_start_time = _timing_time_get();
+}
+
+EINA_UNUSED static void
+_timing_end(void)
+{
+   double diff;
+   static int thres_set = 0;
+   static double thres = 0;
+
+   if (!_timing_enabled()) return;
+   if (!thres_set)
+     {
+        const char *env = getenv("TIME_DIFF_THRESHOLD");
+
+        if (env)
+          {
+             thres = strtod(env, NULL);
+             if (thres > 0)
+               thres_set = 1;
+          }
+        if (!thres_set)
+          thres = 0.0001;
+        thres_set = 1;
+     }
+   diff = _timing_time_get() - _timing_start_time;
+
+   if (diff > thres)
+     printf("TIME %s: %.5g\n", tcase_name(), diff);
+}
+
+# define EFL_START_TEST(TEST_NAME) \
+  START_TEST(TEST_NAME) \
+  { \
+  _timing_start();
+
+# define EFL_END_TEST \
+  _timing_end(); \
+  } \
+  END_TEST
+
+#else
+# define EFL_START_TEST(TEST_NAME) START_TEST(TEST_NAME)
+# define EFL_END_TEST END_TEST
+
+#endif
+
+static char srunner_xml_buf[4096];
+
+static int
+_efl_suite_run_end(SRunner *sr, const char *name)
+{
+   int failed_count;
+
+   if (name)
+     {
+        char *n = strdup(name);
+        char *p;
+
+        for (p = n; p[0]; p++)
+          {
+             switch (p[0])
+               {
+                case ' ':
+                case '/':
+                case '\\':
+                case ';':
+                  p[0] = '_';
+                  break;
+               }
+          }
+        snprintf(srunner_xml_buf, sizeof(srunner_xml_buf), TESTS_BUILD_DIR "/check-results-%s.xml", n);
+        srunner_set_xml(sr, srunner_xml_buf);
+        free(n);
+     }
+   else
+     srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml");
+   srunner_run_all(sr, CK_ENV);
+   failed_count = srunner_ntests_failed(sr);
+   srunner_free(sr);
+   return failed_count;
+}
+
+#ifdef HAVE_FORK
+static EINA_UNUSED Eina_Hash *fork_map;
+
+EINA_UNUSED static int
+_efl_suite_wait_on_fork(int *num_forks, Eina_Bool *timeout)
+{
+   int status = 0, ret, pid;
+   pid = waitpid(0, &status, 0);
+   if (WIFEXITED(status))
+     ret = WEXITSTATUS(status);
+   else
+     ret = 1;
+   if ((timeout_pid > 0) && (pid == timeout_pid))
+     *timeout = EINA_TRUE;
+   else if (timeout_pid > 0)
+     {
+        eina_hash_del_by_key(fork_map, &pid);
+        (*num_forks)--;
+     }
+   return ret;
+}
+#endif
+
+EINA_UNUSED static int
+_efl_suite_build_and_run(int argc, const char **argv, const char *suite_name, const Efl_Test_Case *etc, SFun init, SFun shutdown)
+{
+   Suite *s;
+   SRunner *sr;
+   TCase *tc;
+   int i, failed_count = 0;
+#ifdef HAVE_FORK
+   int do_fork;
+   int num_forks = 0;
+   int can_fork = 0;
+   Eina_Bool timeout_reached = EINA_FALSE;
+# ifdef ENABLE_TIMING_INFO
+   double tcstart = 0.0;
+# endif
+#endif
+#ifdef ENABLE_TIMING_INFO
+   double tstart = 0.0;
+   int timing;
+#endif
+
+#ifdef ENABLE_TIMING_INFO
+   timing = _timing_enabled();
+   if (timing)
+     tstart = _timing_time_get();
+#endif
+
+#ifdef HAVE_FORK
+# ifdef ENABLE_TIMING_INFO
+   if (timing)
+     tcstart = tstart;
+# endif
+#endif
+
+   fflush(stdout);
+   s = suite_create(suite_name);
+   sr = srunner_create(s);
+#ifdef HAVE_FORK
+   do_fork = _efl_test_fork_has(sr);
+   if (do_fork)
+     can_fork = !!etc[1].test_case /* can't parallelize 1 test */;
+#endif
+
+   for (i = 0; etc[i].test_case; ++i)
+     {
+#ifdef HAVE_FORK
+        int pid = 0;
+#endif
+
+        if (!_efl_test_use(argc, argv, etc[i].test_case))
+           continue;
+#ifdef HAVE_FORK
+        if (do_fork && can_fork)
+          {
+             if (!timeout_pid)
+               {
+                  timeout_pid = fork();
+                  if (timeout_pid == 0)
+                    {
+                       int ret = execl(PACKAGE_BUILD_DIR "/src/tests/timeout",
+                                       PACKAGE_BUILD_DIR "/src/tests/timeout",
+                                       (char *)NULL);
+                       if (ret != 0)
+                         {
+                            fprintf(stderr, "EXECL %s TO RUN TIMEOUT!!!\n", PACKAGE_BUILD_DIR "/src/tests/timeout");
+                            perror("EXECL");
+                            fflush(stderr);
+                            abort();
+                         }
+                    }
+                  else if (timeout_pid < 0)
+                    {
+                       fprintf(stderr, "FORK TO RUN TIMEOUT TOOL FAILED!!!\n");
+                       perror("FORK");
+                       fflush(stderr);
+                       abort();
+                    }
+               }
+             if (num_forks == eina_cpu_count())
+               failed_count += _efl_suite_wait_on_fork(&num_forks, &timeout_reached);
+             if (timeout_reached) break;
+             pid = fork();
+             if (pid > 0)
+               {
+                  if (!fork_map) fork_map = eina_hash_int32_new(NULL);
+                  eina_hash_add(fork_map, &pid, etc[i].test_case);
+                  num_forks++;
+# ifdef ENABLE_TIMING_INFO
+                  if (timing)
+                    tcstart = _timing_time_get();
+# endif
+                  continue;
+               }
+            else if (pid < 0)
+              {
+                fprintf(stderr, "FORK TO RUN TIMEOUT TOOL FAILED!!!\n");
+                perror("FORK");
+                fflush(stderr);
+                abort();
+              }
+          }
+#endif
+
+        tc = tcase_create(etc[i].test_case);
+        if (init || shutdown)
+          tcase_add_checked_fixture(tc, init, shutdown);
+
+#ifdef HAVE_FORK
+        if (do_fork)
+          tcase_set_timeout(tc, 0);
+#endif
+
+        etc[i].build(tc);
+        suite_add_tcase(s, tc);
+#ifdef HAVE_FORK
+        if (do_fork && (!pid) && can_fork)
+          {
+             failed_count = _efl_suite_run_end(sr, etc[i].test_case);
+             if (failed_count > 255)
+               failed_count = 255;
+# ifdef ENABLE_TIMING_INFO
+             if (timing)
+               printf("TC TIME %s: %.5g\n", etc[i].test_case, _timing_time_get() - tcstart);
+# endif
+             exit(failed_count);
+          }
+#endif
+     }
+
+#ifdef HAVE_FORK
+   if (num_forks && (!timeout_reached))
+     {
+        do
+          {
+             failed_count += _efl_suite_wait_on_fork(&num_forks, &timeout_reached);
+          } while (num_forks && (!timeout_reached));
+        if (timeout_reached)
+          {
+             Eina_Iterator *it;
+             const char *testname;
+             it = eina_hash_iterator_data_new(fork_map);
+             timeout_pid = 0;
+             printf("FAILSAFE TIMEOUT REACHED!\n");
+             fflush(stdout);
+             EINA_ITERATOR_FOREACH(it, testname)
+               printf("STILL RUNNING: %s\n", testname);
+             fflush(stdout);
+             eina_iterator_free(it);
+             failed_count++;
+          }
+     }
+   else
+#endif
+     failed_count = _efl_suite_run_end(sr, NULL);
+
+#ifdef HAVE_FORK
+   if (timeout_pid)
+     {
+        kill(timeout_pid, SIGKILL);
+        timeout_pid = 0;
+     }
+   eina_hash_free(fork_map);
+   fork_map = NULL;
+#endif
+
+#ifdef ENABLE_TIMING_INFO
+   if (timing)
+     {
+        printf("SUITE TIME(%u) %s: %.5g\n", getpid(), suite_name, _timing_time_get() - tstart);
+        fflush(stdout);
+     }
+#endif
+   return failed_count;
+}
+
+#define SUITE_INIT(NAME) static void _##NAME##_suite_init(void)
+#define SUITE_INIT_FN(NAME) _##NAME##_suite_init
+#define SUITE_SHUTDOWN(NAME) static void _##NAME##_suite_shutdown(void)
+#define SUITE_SHUTDOWN_FN(NAME) _##NAME##_suite_shutdown
+
+#endif
diff --git a/src/tests/meson.build b/src/tests/meson.build
new file mode 100644
index 000000000..0f2a9ce30
--- /dev/null
+++ b/src/tests/meson.build
@@ -0,0 +1,11 @@
+# Test suites, built only with -Dtests=true.
+#
+# The .c files sitting directly in this directory are older standalone X11
+# clients driven by hand; they are deliberately left out of the build.
+
+# Watchdog helper forked by efl_check.h when running suites in fork mode.
+executable('timeout', 'timeout.c')
+
+if get_option('wl') == true
+  subdir('wayland')
+endif
diff --git a/src/tests/timeout.c b/src/tests/timeout.c
new file mode 100644
index 000000000..c3433970d
--- /dev/null
+++ b/src/tests/timeout.c
@@ -0,0 +1,17 @@
+/* Watchdog helper for efl_check.h's fork mode. Copied from core/efl
+ * src/tests/timeout.c. */
+#include <unistd.h>
+
+#if defined(__clang__)
+# pragma clang diagnostic ignored "-Wunused-parameter"
+#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
+# pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+
+int
+main(int arc, char *argv[])
+{
+   sleep(240);
+   return 0;
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to