From 884338cff4c64eb2a16fb20e78dd5dce6b2f5e39 Mon Sep 17 00:00:00 2001 From: Michele Pagot Date: Thu, 10 Apr 2025 01:55:30 +0200 Subject: [PATCH] Add some tests about config Create a test infrastructure, create few tests about the config file reading and validation. Add couple of checks in config.c to avoid null pointers exceptions when running tests. --- .gitignore | 1 - meson.build | 25 ++--- sway/config.c | 26 +++-- sway/meson.build | 19 +++- sway/test/empty_config.txt | 0 sway/test/log_stub.c | 26 +++++ sway/test/test_config.c | 214 +++++++++++++++++++++++++++++++++++++ 7 files changed, 287 insertions(+), 24 deletions(-) create mode 100644 sway/test/empty_config.txt create mode 100644 sway/test/log_stub.c create mode 100644 sway/test/test_config.c diff --git a/.gitignore b/.gitignore index 167960e2..3ccacdca 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ install_manifest.txt *.o *.a bin/ -test/ build/ build-*/ .cache/ diff --git a/meson.build b/meson.build index 9ce5723e..8c74702a 100644 --- a/meson.build +++ b/meson.build @@ -186,6 +186,19 @@ else ) endif +# subdir('sway') needs reference_config_file +# as input for its tests +config = configuration_data() +config.set('datadir', join_paths(prefix, datadir)) +config.set('prefix', prefix) +config.set('sysconfdir', join_paths(prefix, sysconfdir)) + +reference_config_file = configure_file( + configuration: config, + input: 'config.in', + output: '@BASENAME@', + install_dir: join_paths(sysconfdir, 'sway') +) sway_inc = include_directories('include') @@ -205,18 +218,6 @@ if get_option('swaynag') subdir('swaynag') endif -config = configuration_data() -config.set('datadir', join_paths(prefix, datadir)) -config.set('prefix', prefix) -config.set('sysconfdir', join_paths(prefix, sysconfdir)) - -configure_file( - configuration: config, - input: 'config.in', - output: '@BASENAME@', - install_dir: join_paths(sysconfdir, 'sway') -) - install_data( 'sway.desktop', install_dir: join_paths(datadir, 'wayland-sessions') diff --git a/sway/config.c b/sway/config.c index ec705968..eaf5bfb0 100644 --- a/sway/config.c +++ b/sway/config.c @@ -40,6 +40,10 @@ struct sway_config *config = NULL; static struct xkb_state *keysym_translation_state_create( struct xkb_rule_names rules, uint32_t context_flags) { struct xkb_context *context = xkb_context_new(context_flags | XKB_CONTEXT_NO_SECURE_GETENV); + if (!context) { + sway_log(SWAY_ERROR, "Failed to create XKB context"); + return NULL; + } struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_names( context, &rules, @@ -477,22 +481,24 @@ bool load_main_config(const char *file, bool is_active, bool validating) { config->active = true; // xwayland can only be enabled/disabled at launch - sway_log(SWAY_DEBUG, "xwayland will remain %s", + if(old_config != NULL) { + sway_log(SWAY_DEBUG, "xwayland will remain %s", old_config->xwayland ? "enabled" : "disabled"); - config->xwayland = old_config->xwayland; + config->xwayland = old_config->xwayland; - // primary_selection can only be enabled/disabled at launch - sway_log(SWAY_DEBUG, "primary_selection will remain %s", + // primary_selection can only be enabled/disabled at launch + sway_log(SWAY_DEBUG, "primary_selection will remain %s", old_config->primary_selection ? "enabled" : "disabled"); - config->primary_selection = old_config->primary_selection; + config->primary_selection = old_config->primary_selection; - if (!config->validating) { - if (old_config->swaybg_client != NULL) { + if (!config->validating) { + if (old_config->swaybg_client != NULL) { wl_client_destroy(old_config->swaybg_client); - } + } - if (old_config->swaynag_config_errors.client != NULL) { - wl_client_destroy(old_config->swaynag_config_errors.client); + if (old_config->swaynag_config_errors.client != NULL) { + wl_client_destroy(old_config->swaynag_config_errors.client); + } } input_manager_reset_all_inputs(); diff --git a/sway/meson.build b/sway/meson.build index 8042c89b..51340803 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -169,7 +169,7 @@ sway_sources = files( 'commands/input/middle_emulation.c', 'commands/input/natural_scroll.c', 'commands/input/pointer_accel.c', - 'commands/input/rotation_angle.c', + 'commands/input/rotation_angle.c', 'commands/input/repeat_delay.c', 'commands/input/repeat_rate.c', 'commands/input/scroll_button.c', @@ -252,3 +252,20 @@ executable( link_with: [lib_sway_common], install: true ) +test_config = executable('sway_test_config', + [ + 'config.c', + 'test/test_config.c', + 'test/log_stub.c', + '../common/stringop.c', + '../common/util.c', + '../common/list.c'] + wl_protos_src, + include_directories: [sway_inc, include_directories('test')], + dependencies: sway_deps) + + +empty_config = meson.current_source_dir() + '/test/empty_config.txt' +test('sway_test_empty_config', test_config, args: ['-c', empty_config]) +test('sway_test_empty_config_validate', test_config, args: ['-c', empty_config, '-C']) +test('sway_test_empty_config_validate_activate', test_config, args: ['-c', empty_config, '-C', '-A']) +test('sway_test_reference_config_validate_activate', test_config, args: ['-c', reference_config_file, '-C', '-A']) diff --git a/sway/test/empty_config.txt b/sway/test/empty_config.txt new file mode 100644 index 00000000..e69de29b diff --git a/sway/test/log_stub.c b/sway/test/log_stub.c new file mode 100644 index 00000000..e8795635 --- /dev/null +++ b/sway/test/log_stub.c @@ -0,0 +1,26 @@ +#include +#include "log.h" + + +void sway_log_init(sway_log_importance_t verbosity, terminate_callback_t callback) { + return; +} + +void _sway_log(sway_log_importance_t verbosity, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +void _sway_vlog(sway_log_importance_t verbosity, const char *fmt, va_list args) { + vfprintf(stderr, fmt, args); +} + +bool _sway_assert(bool condition, const char *format, ...) { + return true; +} + +void _sway_abort(const char *format, ...) { + return; +} \ No newline at end of file diff --git a/sway/test/test_config.c b/sway/test/test_config.c new file mode 100644 index 00000000..530f6fee --- /dev/null +++ b/sway/test/test_config.c @@ -0,0 +1,214 @@ +#include "sway/config.h" +#include "sway/output.h" +#include "sway/commands.h" +#include "sway/server.h" +#include "sway/criteria.h" +#include "pango.h" + +void free_gesture_binding(struct sway_gesture_binding *binding) { + return; +} + +void free_bar_config(struct bar_config *bar) { + return; +} + +void free_sway_binding(struct sway_binding *binding) { + return; +} + +void free_switch_binding(struct sway_switch_binding *binding) { + return; +} + +void free_sway_variable(struct sway_variable *var) { + return; +} + +bool translate_binding(struct sway_binding *binding) { + return true; +} + +void input_config_fill_rule_names(struct input_config *ic, + struct xkb_rule_names *rules) { + return; +} + +void binding_add_translated(struct sway_binding *binding, + list_t *mode_bindings) { + return; +} + +int seat_name_cmp(const void *item, const void *data) { + return 0; +} + +void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { + return; +} + +void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, + const char *fmt, ...) { + return; +} + +void swaynag_show(struct swaynag_instance *swaynag) { + return; +} + +struct cmd_results *config_commands_command(char *exec) { + struct cmd_results *results = NULL; + results = cmd_results_new(CMD_SUCCESS, NULL); + return results; +} + +list_t *execute_command(char *_exec, struct sway_seat *seat, + struct sway_container *con) { + list_t *res_list = create_list(); + + if (!res_list) { + return NULL; + } + return res_list; +} + +struct cmd_results *config_command(char *exec, char **new_block) { + struct cmd_results *results = NULL; + results = cmd_results_new(CMD_SUCCESS, NULL); + return results; +} + +struct cmd_results *cmd_results_new(enum cmd_status status, + const char *format, ...) { +struct cmd_results *results = malloc(sizeof(struct cmd_results)); +return results; +} + +void free_cmd_results(struct cmd_results *results) { + free(results); +} + +void get_text_metrics(const PangoFontDescription *description, int *height, int *baseline) { + return; +} + +void request_modeset(void) { + return; +} + + +void sway_switch_retrigger_bindings_for_all(void) { + return; +} + +void input_manager_reset_all_inputs(void) { + return; +} + +struct sway_seat *input_manager_get_seat(const char *seat_name, bool create) { + struct sway_seat *seat = NULL; + return seat; +} + +void input_manager_verify_fallback_seat(void) { + return; +} + +void seat_destroy(struct sway_seat *seat) { + return; +} + +void free_workspace_config(struct workspace_config *wsc) { + return; +} + +void free_output_config(struct output_config *oc) { + return; +} + +void free_input_config(struct input_config *ic) { + return; +} + +void free_seat_config(struct seat_config *seat) { + return; +} + +void criteria_destroy(struct criteria *criteria) { + return; +} + +void input_manager_apply_input_config(struct input_config *input_config) { + return; +} + +void input_manager_apply_seat_config(struct seat_config *seat_config) { + return; +} + +void arrange_root(void) { + return; +} + +bool spawn_swaybg(void) { + return true; +} + +struct sway_server server = {0}; + + +#include + +static const struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"config", required_argument, NULL, 'c'}, + {"validate", no_argument, NULL, 'C'}, + {"active", no_argument, NULL, 'A'}, + {0, 0, 0, 0} +}; + +static const char usage[] = + "Usage: sway_test_config [options]\n" + "\n" + " -h, --help Show help message and quit.\n" + " -c, --config Specify a config file.\n" + " -C, --validate Check the validity of the config file, then exit.\n" + " -A, --active Set is_active to true.\n" + "\n"; + +int main(int argc, char **argv) { + bool active = false, validate = false, res; + + char *config_path = NULL; + + int c; + while (1) { + int option_index = 0; + c = getopt_long(argc, argv, "hCAc:", long_options, &option_index); + if (c == -1) { + break; + } + switch (c) { + case 'h': // help + printf("%s", usage); + exit(EXIT_SUCCESS); + break; + case 'c': + //free(config_path); + config_path = strdup(optarg); + break; + case 'C': + validate = true; + break; + case 'A': + active = true; + break; + default: + fprintf(stderr, "%s", usage); + exit(EXIT_FAILURE); + } + } + + res = load_main_config(config_path, active, validate); + return res ? 0 : 1; +} \ No newline at end of file