foot/tests/test-config.c

906 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#if !defined(_DEBUG)
#define _DEBUG
#endif
#undef NDEBUG
#include "../log.h"
#include "../config.c"
#define ALEN(v) (sizeof(v) / sizeof((v)[0]))
/*
* Stubs
*/
void
user_notification_add_fmt(user_notifications_t *notifications,
enum user_notification_kind kind,
const char *fmt, ...)
{
}
static void
test_invalid_key(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key)
{
ctx->key = key;
ctx->value = "value for invalid key";
if (parse_fun(ctx)) {
BUG("[%s].%s: did not fail to parse as expected"
"(key should be invalid)", ctx->section, ctx->key);
}
}
static void
test_string(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key, char *const *conf_ptr)
{
ctx->key = key;
static const struct {
const char *option_string;
const char *value;
bool invalid;
} input[] = {
{"a string", "a string"},
};
for (size_t i = 0; i < ALEN(input); i++) {
ctx->value = input[i].option_string;
if (input[i].invalid) {
if (parse_fun(ctx)) {
BUG("[%s].%s=%s: did not fail to parse as expected",
ctx->section, ctx->key, ctx->value);
}
} else {
if (!parse_fun(ctx)) {
BUG("[%s].%s=%s: failed to parse",
ctx->section, ctx->key, ctx->value);
}
if (strcmp(*conf_ptr, input[i].value) != 0) {
BUG("[%s].%s=%s: set value (%s) not the expected one (%s)",
ctx->section, ctx->key, ctx->value,
*conf_ptr, input[i].value);
}
}
}
}
static void
test_wstring(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key, wchar_t *const *conf_ptr)
{
ctx->key = key;
static const struct {
const char *option_string;
const wchar_t *value;
bool invalid;
} input[] = {
{"a string", L"a string"},
};
for (size_t i = 0; i < ALEN(input); i++) {
ctx->value = input[i].option_string;
if (input[i].invalid) {
if (parse_fun(ctx)) {
BUG("[%s].%s=%s: did not fail to parse as expected",
ctx->section, ctx->key, ctx->value);
}
} else {
if (!parse_fun(ctx)) {
BUG("[%s].%s=%s: failed to parse",
ctx->section, ctx->key, ctx->value);
}
if (wcscmp(*conf_ptr, input[i].value) != 0) {
BUG("[%s].%s=%s: set value (%ls) not the expected one (%ls)",
ctx->section, ctx->key, ctx->value,
*conf_ptr, input[i].value);
}
}
}
}
static void
test_boolean(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key, const bool *conf_ptr)
{
ctx->key = key;
static const struct {
const char *option_string;
bool value;
bool invalid;
} input[] = {
{"1", true}, {"0", false},
{"on", true}, {"off", false},
{"true", true}, {"false", false},
{"unittest-invalid-boolean-value", false, true},
};
for (size_t i = 0; i < ALEN(input); i++) {
ctx->value = input[i].option_string;
if (input[i].invalid) {
if (parse_fun(ctx)) {
BUG("[%s].%s=%s: did not fail to parse as expected",
ctx->section, ctx->key, ctx->value);
}
} else {
if (!parse_fun(ctx)) {
BUG("[%s].%s=%s: failed to parse",
ctx->section, ctx->key, ctx->value);
}
if (*conf_ptr != input[i].value) {
BUG("[%s].%s=%s: set value (%s) not the expected one (%s)",
ctx->section, ctx->key, ctx->value,
*conf_ptr ? "true" : "false",
input[i].value ? "true" : "false");
}
}
}
}
static void
test_uint16(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key, const uint16_t *conf_ptr)
{
ctx->key = key;
static const struct {
const char *option_string;
uint16_t value;
bool invalid;
} input[] = {
{"0", 0}, {"65535", 65535}, {"65536", 0, true},
{"abc", 0, true}, {"true", 0, true},
};
for (size_t i = 0; i < ALEN(input); i++) {
ctx->value = input[i].option_string;
if (input[i].invalid) {
if (parse_fun(ctx)) {
BUG("[%s].%s=%s: did not fail to parse as expected",
ctx->section, ctx->key, ctx->value);
}
} else {
if (!parse_fun(ctx)) {
BUG("[%s].%s=%s: failed to parse",
ctx->section, ctx->key, ctx->value);
}
if (*conf_ptr != input[i].value) {
BUG("[%s].%s=%s: set value (%hu) not the expected one (%hu)",
ctx->section, ctx->key, ctx->value,
*conf_ptr, input[i].value);
}
}
}
}
static void
test_uint32(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key, const uint32_t *conf_ptr)
{
ctx->key = key;
static const struct {
const char *option_string;
uint32_t value;
bool invalid;
} input[] = {
{"0", 0}, {"65536", 65536}, {"4294967295", 4294967295},
{"4294967296", 0, true}, {"abc", 0, true}, {"true", 0, true},
};
for (size_t i = 0; i < ALEN(input); i++) {
ctx->value = input[i].option_string;
if (input[i].invalid) {
if (parse_fun(ctx)) {
BUG("[%s].%s=%s: did not fail to parse as expected",
ctx->section, ctx->key, ctx->value);
}
} else {
if (!parse_fun(ctx)) {
BUG("[%s].%s=%s: failed to parse",
ctx->section, ctx->key, ctx->value);
}
if (*conf_ptr != input[i].value) {
BUG("[%s].%s=%s: set value (%u) not the expected one (%u)",
ctx->section, ctx->key, ctx->value,
*conf_ptr, input[i].value);
}
}
}
}
static void
test_double(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key, const float *conf_ptr)
{
ctx->key = key;
static const struct {
const char *option_string;
float value;
bool invalid;
} input[] = {
{"0", 0}, {"0.1", 0.1}, {"1e10", 1e10}, {"-10.7", -10.7},
{"abc", 0, true}, {"true", 0, true},
};
for (size_t i = 0; i < ALEN(input); i++) {
ctx->value = input[i].option_string;
if (input[i].invalid) {
if (parse_fun(ctx)) {
BUG("[%s].%s=%s: did not fail to parse as expected",
ctx->section, ctx->key, ctx->value);
}
} else {
if (!parse_fun(ctx)) {
BUG("[%s].%s=%s: failed to parse",
ctx->section, ctx->key, ctx->value);
}
if (*conf_ptr != input[i].value) {
BUG("[%s].%s=%s: set value (%f) not the expected one (%f)",
ctx->section, ctx->key, ctx->value,
*conf_ptr, input[i].value);
}
}
}
}
static void
test_pt_or_px(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key, const struct pt_or_px *conf_ptr)
{
ctx->key = key;
static const struct {
const char *option_string;
struct pt_or_px value;
bool invalid;
} input[] = {
{"12", {.pt = 12}}, {"12px", {.px = 12}},
{"unittest-invalid-pt-or-px-value", {0}, true},
};
for (size_t i = 0; i < ALEN(input); i++) {
ctx->value = input[i].option_string;
if (input[i].invalid) {
if (parse_fun(ctx)) {
BUG("[%s].%s=%s: did not fail to parse as expected",
ctx->section, ctx->key, ctx->value);
}
} else {
if (!parse_fun(ctx)) {
BUG("[%s].%s=%s: failed to parse",
ctx->section, ctx->key, ctx->value);
}
if (memcmp(conf_ptr, &input[i].value, sizeof(*conf_ptr)) != 0) {
BUG("[%s].%s=%s: "
"set value (pt=%f, px=%d) not the expected one (pt=%f, px=%d)",
ctx->section, ctx->key, ctx->value,
conf_ptr->pt, conf_ptr->px,
input[i].value.pt, input[i].value.px);
}
}
}
}
static void
test_spawn_template(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key, const struct config_spawn_template *ptr)
{
static const char *const args[] = {
"command", "arg1", "arg2", "arg3 has spaces"};
ctx->key = key;
ctx->value = "command arg1 arg2 \"arg3 has spaces\"";
if (!parse_fun(ctx))
BUG("[%s].%s=%s: failed to parse", ctx->section, ctx->key, ctx->value);
if (ptr->argv.args == NULL)
BUG("[%s].%s=%s: argv is NULL", ctx->section, ctx->key, ctx->value);
for (size_t i = 0; i < ALEN(args); i++) {
if (ptr->argv.args[i] == NULL ||
strcmp(ptr->argv.args[i], args[i]) != 0)
{
BUG("[%s].%s=%s: set value not the expected one: "
"mismatch of arg #%zu: expected=\"%s\", got=\"%s\"",
ctx->section, ctx->key, ctx->value, i,
args[i], ptr->argv.args[i]);
}
}
if (ptr->argv.args[ALEN(args)] != NULL) {
BUG("[%s].%s=%s: set value not the expected one: "
"expected NULL terminator at arg #%zu, got=\"%s\"",
ctx->section, ctx->key, ctx->value,
ALEN(args), ptr->argv.args[ALEN(args)]);
}
/* Trigger parse failure */
ctx->value = "command with \"unterminated quote";
if (parse_fun(ctx)) {
BUG("[%s].%s=%s: did not fail to parse as expected",
ctx->section, ctx->key, ctx->value);
}
}
static void
test_enum(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key, size_t count, const char *enum_strings[static count],
int enum_values[static count], int *ptr)
{
ctx->key = key;
for (size_t i = 0; i < count; i++) {
ctx->value = enum_strings[i];
if (!parse_fun(ctx)) {
BUG("[%s].%s=%s: failed to parse",
ctx->section, ctx->key, ctx->value);
}
if (*ptr != enum_values[i]) {
BUG("[%s].%s=%s: set value not the expected one: expected %d, got %d",
ctx->section, ctx->key, ctx->value, enum_values[i], *ptr);
}
}
ctx->value = "invalid-enum-value";
if (parse_fun(ctx)) {
BUG("[%s].%s=%s: did not fail to parse as expeced",
ctx->section, ctx->key, ctx->value);
}
}
static void
test_section_main(void)
{
struct config conf = {0};
struct context ctx = {.conf = &conf, .section = "main", .path = "unittest"};
test_invalid_key(&ctx, &parse_section_main, "invalid-key");
test_string(&ctx, &parse_section_main, "shell", &conf.shell);
test_string(&ctx, &parse_section_main, "term", &conf.term);
test_string(&ctx, &parse_section_main, "app-id", &conf.app_id);
test_wstring(&ctx, &parse_section_main, "word-delimiters", &conf.word_delimiters);
test_boolean(&ctx, &parse_section_main, "login-shell", &conf.login_shell);
test_boolean(&ctx, &parse_section_main, "box-drawings-uses-font-glyphs", &conf.box_drawings_uses_font_glyphs);
test_boolean(&ctx, &parse_section_main, "locked-title", &conf.locked_title);
test_boolean(&ctx, &parse_section_main, "notify-focus-inhibit", &conf.notify_focus_inhibit);
test_pt_or_px(&ctx, &parse_section_main, "line-height", &conf.line_height);
test_pt_or_px(&ctx, &parse_section_main, "letter-spacing", &conf.letter_spacing);
test_pt_or_px(&ctx, &parse_section_main, "horizontal-letter-offset", &conf.horizontal_letter_offset);
test_pt_or_px(&ctx, &parse_section_main, "vertical-letter-offset", &conf.vertical_letter_offset);
test_uint16(&ctx, &parse_section_main, "resize-delay-ms", &conf.resize_delay_ms);
test_uint16(&ctx, &parse_section_main, "workers", &conf.render_worker_count);
test_spawn_template(&ctx, &parse_section_main, "notify", &conf.notify);
test_enum(
&ctx, &parse_section_main, "dpi-aware",
9,
(const char *[]){"on", "true", "yes", "1",
"off", "false", "no", "0",
"auto"},
(int []){DPI_AWARE_YES, DPI_AWARE_YES, DPI_AWARE_YES, DPI_AWARE_YES,
DPI_AWARE_NO, DPI_AWARE_NO, DPI_AWARE_NO, DPI_AWARE_NO,
DPI_AWARE_AUTO},
(int *)&conf.dpi_aware);
test_enum(&ctx, &parse_section_main, "selection-target",
4,
(const char *[]){"none", "primary", "clipboard", "both"},
(int []){SELECTION_TARGET_NONE,
SELECTION_TARGET_PRIMARY,
SELECTION_TARGET_CLIPBOARD,
SELECTION_TARGET_BOTH},
(int *)&conf.selection_target);
test_enum(
&ctx, &parse_section_main, "initial-window-mode",
3,
(const char *[]){"windowed", "maximized", "fullscreen"},
(int []){STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN},
(int *)&conf.startup_mode);
/* TODO: font (custom) */
/* TODO: include (custom) */
/* TODO: bold-text-in-bright (enum/boolean) */
/* TODO: pad (geometry + optional string)*/
/* TODO: initial-window-size-pixels (geometry) */
/* TODO: initial-window-size-chars (geometry) */
config_free(conf);
}
static void
test_section_bell(void)
{
struct config conf = {0};
struct context ctx = {.conf = &conf, .section = "bell", .path = "unittest"};
test_invalid_key(&ctx, &parse_section_bell, "invalid-key");
test_boolean(&ctx, &parse_section_bell, "urgent", &conf.bell.urgent);
test_boolean(&ctx, &parse_section_bell, "notify", &conf.bell.notify);
test_boolean(&ctx, &parse_section_bell, "command-focused",
&conf.bell.command_focused);
test_spawn_template(&ctx, &parse_section_bell, "command",
&conf.bell.command);
config_free(conf);
}
static void
test_section_scrollback(void)
{
struct config conf = {0};
struct context ctx = {
.conf = &conf, .section = "scrollback", .path = "unittest"};
test_invalid_key(&ctx, &parse_section_scrollback, "invalid-key");
test_uint32(&ctx, &parse_section_scrollback, "lines",
&conf.scrollback.lines);
test_double(&ctx, parse_section_scrollback, "multiplier", &conf.scrollback.multiplier);
/* TODO: indicator-position (enum) */
/* TODO: indicator-format (enum, sort-of) */
config_free(conf);
}
static void
test_key_binding(struct context *ctx, bool (*parse_fun)(struct context *ctx),
int action, int max_action, const char *const *map,
struct config_key_binding_list *bindings,
enum config_key_binding_type type)
{
xassert(map[action] != NULL);
xassert(bindings->count == 0);
const char *key = map[action];
/* “Randomize” which modifiers to enable */
const bool ctrl = action % 2;
const bool alt = action % 3;
const bool shift = action % 4;
const bool super = action % 5;
const bool argv = action % 6;
static const char *const args[] = {
"command", "arg1", "arg2", "arg3 has spaces"};
/* Generate the modifier part of the value */
char modifier_string[32];
sprintf(modifier_string, "%s%s%s%s",
ctrl ? XKB_MOD_NAME_CTRL "+" : "",
alt ? XKB_MOD_NAME_ALT "+" : "",
shift ? XKB_MOD_NAME_SHIFT "+" : "",
super ? XKB_MOD_NAME_LOGO "+" : "");
/* Use a unique symbol for this action (key bindings) */
const xkb_keysym_t sym = XKB_KEY_a + action;
/* Mouse button (mouse bindings) */
const int button_idx = action % ALEN(button_map);
const int button = button_map[button_idx].code;
const int click_count = action % 3 + 1;
/* Finally, generate the value (e.g. “Control+shift+x”) */
char value[128] = {0};
ctx->key = key;
ctx->value = value;
/* First, try setting the empty string */
if (parse_fun(ctx)) {
BUG("[%s].%s=<empty>: did not fail to parse as expected",
ctx->section, ctx->key);
}
switch (type) {
case KEY_BINDING: {
char sym_name[16];
xkb_keysym_get_name(sym, sym_name, sizeof(sym_name));
snprintf(value, sizeof(value), "%s%s%s",
argv ? "[command arg1 arg2 \"arg3 has spaces\"] " : "",
modifier_string, sym_name);
break;
}
case MOUSE_BINDING: {
const char *const button_name = button_map[button_idx].name;
int chars = snprintf(
value, sizeof(value), "%s%s%s",
argv ? "[command arg1 arg2 \"arg3 has spaces\"] " : "",
modifier_string, button_name);
xassert(click_count > 0);
if (click_count > 1)
snprintf(&value[chars], sizeof(value) - chars, "-%d", click_count);
break;
}
}
if (!parse_fun(ctx)) {
BUG("[%s].%s=%s failed to parse",
ctx->section, ctx->key, ctx->value);
}
const struct config_key_binding *binding =
&bindings->arr[bindings->count - 1];
if (argv) {
if (binding->pipe.argv.args == NULL) {
BUG("[%s].%s=%s: pipe argv is NULL",
ctx->section, ctx->key, ctx->value);
}
for (size_t i = 0; i < ALEN(args); i++) {
if (binding->pipe.argv.args[i] == NULL ||
strcmp(binding->pipe.argv.args[i], args[i]) != 0)
{
BUG("[%s].%s=%s: pipe argv not the expected one: "
"mismatch of arg #%zu: expected=\"%s\", got=\"%s\"",
ctx->section, ctx->key, ctx->value, i,
args[i], binding->pipe.argv.args[i]);
}
}
if (binding->pipe.argv.args[ALEN(args)] != NULL) {
BUG("[%s].%s=%s: pipe argv not the expected one: "
"expected NULL terminator at arg #%zu, got=\"%s\"",
ctx->section, ctx->key, ctx->value,
ALEN(args), binding->pipe.argv.args[ALEN(args)]);
}
} else {
if (binding->pipe.argv.args != NULL) {
BUG("[%s].%s=%s: pipe argv not NULL",
ctx->section, ctx->key, ctx->value);
}
}
if (binding->action != action) {
BUG("[%s].%s=%s: action mismatch: %d != %d",
ctx->section, ctx->key, ctx->value, binding->action, action);
}
if (binding->modifiers.ctrl != ctrl ||
binding->modifiers.alt != alt ||
binding->modifiers.shift != shift ||
binding->modifiers.super != super)
{
BUG("[%s].%s=%s: modifier mismatch:\n"
" have: ctrl=%d, alt=%d, shift=%d, super=%d\n"
" expected: ctrl=%d, alt=%d, shift=%d, super=%d",
ctx->section, ctx->key, ctx->value,
binding->modifiers.ctrl, binding->modifiers.alt,
binding->modifiers.shift, binding->modifiers.super,
ctrl, alt, shift, super);
}
switch (type) {
case KEY_BINDING:
if (binding->k.sym != sym) {
BUG("[%s].%s=%s: key symbol mismatch: %d != %d",
ctx->section, ctx->key, ctx->value, binding->k.sym, sym);
}
break;
case MOUSE_BINDING:;
if (binding->m.button != button) {
BUG("[%s].%s=%s: mouse button mismatch: %d != %d",
ctx->section, ctx->key, ctx->value, binding->m.button, button);
}
if (binding->m.count != click_count) {
BUG("[%s].%s=%s: mouse button click count mismatch: %d != %d",
ctx->section, ctx->key, ctx->value,
binding->m.count, click_count);
}
break;
}
free_key_binding_list(bindings);
}
enum collision_test_mode {
FAIL_DIFFERENT_ACTION,
FAIL_DIFFERENT_ARGV,
FAIL_MOUSE_OVERRIDE,
SUCCED_SAME_ACTION_AND_ARGV,
};
static void
_test_binding_collisions(struct context *ctx,
int max_action, const char *const *map,
enum config_key_binding_type type,
enum collision_test_mode test_mode)
{
struct config_key_binding *bindings_array =
xcalloc(2, sizeof(bindings_array[0]));
struct config_key_binding_list bindings = {
.count = 2,
.arr = bindings_array,
};
/* First, verify we get a collision when trying to assign the same
* key combo to multiple actions */
bindings.arr[0] = (struct config_key_binding){
.action = (test_mode == FAIL_DIFFERENT_ACTION
? max_action - 1 : max_action),
.modifiers = {.ctrl = true},
.path = "unittest",
};
bindings.arr[1] = (struct config_key_binding){
.action = max_action,
.modifiers = {.ctrl = true},
.path = "unittest",
};
switch (type) {
case KEY_BINDING:
bindings.arr[0].k.sym = XKB_KEY_a;
bindings.arr[1].k.sym = XKB_KEY_a;
break;
case MOUSE_BINDING:
bindings.arr[0].m.button = BTN_LEFT;
bindings.arr[0].m.count = 1;
bindings.arr[1].m.button = BTN_LEFT;
bindings.arr[1].m.count = 1;
break;
}
switch (test_mode) {
case FAIL_DIFFERENT_ACTION:
break;
case FAIL_MOUSE_OVERRIDE:
ctx->conf->mouse.selection_override_modifiers.ctrl = true;
break;
case FAIL_DIFFERENT_ARGV:
case SUCCED_SAME_ACTION_AND_ARGV:
bindings.arr[0].pipe.master_copy = true;
bindings.arr[0].pipe.argv.args = xcalloc(
4, sizeof(bindings.arr[0].pipe.argv.args[0]));
bindings.arr[0].pipe.argv.args[0] = xstrdup("/usr/bin/foobar");
bindings.arr[0].pipe.argv.args[1] = xstrdup("hello");
bindings.arr[0].pipe.argv.args[2] = xstrdup("world");
bindings.arr[1].pipe.master_copy = true;
bindings.arr[1].pipe.argv.args = xcalloc(
4, sizeof(bindings.arr[1].pipe.argv.args[0]));
bindings.arr[1].pipe.argv.args[0] = xstrdup("/usr/bin/foobar");
bindings.arr[1].pipe.argv.args[1] = xstrdup("hello");
if (test_mode == SUCCED_SAME_ACTION_AND_ARGV)
bindings.arr[1].pipe.argv.args[2] = xstrdup("world");
break;
}
bool expected_result =
test_mode == SUCCED_SAME_ACTION_AND_ARGV ? true : false;
if (resolve_key_binding_collisions(
ctx->conf, ctx->section, map, &bindings, type) != expected_result)
{
BUG("[%s].%s vs. %s: %s",
ctx->section, map[max_action - 1], map[max_action],
(expected_result == true
? "invalid key combo collision detected"
: "key combo collision not detected"));
}
if (expected_result == false) {
if (bindings.count != 1)
BUG("[%s]: colliding binding not removed", ctx->section);
if (bindings.arr[0].action !=
(test_mode == FAIL_DIFFERENT_ACTION ? max_action - 1 : max_action))
{
BUG("[%s]: wrong binding removed", ctx->section);
}
}
free_key_binding_list(&bindings);
}
static void
test_binding_collisions(struct context *ctx,
int max_action, const char *const *map,
enum config_key_binding_type type)
{
_test_binding_collisions(ctx, max_action, map, type, FAIL_DIFFERENT_ACTION);
_test_binding_collisions(ctx, max_action, map, type, FAIL_DIFFERENT_ARGV);
_test_binding_collisions(ctx, max_action, map, type, SUCCED_SAME_ACTION_AND_ARGV);
if (type == MOUSE_BINDING) {
_test_binding_collisions(
ctx, max_action, map, type, FAIL_MOUSE_OVERRIDE);
}
}
static void
test_section_key_bindings(void)
{
struct config conf = {0};
struct context ctx = {
.conf = &conf, .section = "key-bindings", .path = "unittest"};
test_invalid_key(&ctx, &parse_section_key_bindings, "invalid-key");
for (int action = 0; action < BIND_ACTION_KEY_COUNT; action++) {
if (binding_action_map[action] == NULL)
continue;
test_key_binding(
&ctx, &parse_section_key_bindings,
action, BIND_ACTION_KEY_COUNT - 1,
binding_action_map, &conf.bindings.key, KEY_BINDING);
}
config_free(conf);
}
static void
test_section_key_bindings_collisions(void)
{
struct config conf = {0};
struct context ctx = {
.conf = &conf, .section = "key-bindings", .path = "unittest"};
test_binding_collisions(
&ctx, BIND_ACTION_KEY_COUNT - 1, binding_action_map, KEY_BINDING);
config_free(conf);
}
static void
test_section_search_bindings(void)
{
struct config conf = {0};
struct context ctx = {
.conf = &conf, .section = "search-bindings", .path = "unittest"};
test_invalid_key(&ctx, &parse_section_search_bindings, "invalid-key");
for (int action = 0; action < BIND_ACTION_SEARCH_COUNT; action++) {
if (search_binding_action_map[action] == NULL)
continue;
test_key_binding(
&ctx, &parse_section_search_bindings,
action, BIND_ACTION_SEARCH_COUNT - 1,
search_binding_action_map, &conf.bindings.search, KEY_BINDING);
}
config_free(conf);
}
static void
test_section_search_bindings_collisions(void)
{
struct config conf = {0};
struct context ctx = {
.conf = &conf, .section = "search-bindings", .path = "unittest"};
test_binding_collisions(
&ctx,
BIND_ACTION_SEARCH_COUNT - 1, search_binding_action_map, KEY_BINDING);
config_free(conf);
}
static void
test_section_url_bindings(void)
{
struct config conf = {0};
struct context ctx = {
.conf = &conf, .section = "rul-bindings", .path = "unittest"};
test_invalid_key(&ctx, &parse_section_url_bindings, "invalid-key");
for (int action = 0; action < BIND_ACTION_URL_COUNT; action++) {
if (url_binding_action_map[action] == NULL)
continue;
test_key_binding(
&ctx, &parse_section_url_bindings,
action, BIND_ACTION_URL_COUNT - 1,
url_binding_action_map, &conf.bindings.url, KEY_BINDING);
}
config_free(conf);
}
static void
test_section_url_bindings_collisions(void)
{
struct config conf = {0};
struct context ctx = {
.conf = &conf, .section = "url-bindings", .path = "unittest"};
test_binding_collisions(
&ctx,
BIND_ACTION_URL_COUNT - 1, url_binding_action_map, KEY_BINDING);
config_free(conf);
}
static void
test_section_mouse_bindings(void)
{
struct config conf = {0};
struct context ctx = {
.conf = &conf, .section = "mouse-bindings", .path = "unittest"};
test_invalid_key(&ctx, &parse_section_mouse_bindings, "invalid-key");
for (int action = 0; action < BIND_ACTION_COUNT; action++) {
if (binding_action_map[action] == NULL)
continue;
test_key_binding(
&ctx, &parse_section_mouse_bindings,
action, BIND_ACTION_COUNT - 1,
binding_action_map, &conf.bindings.mouse, MOUSE_BINDING);
}
config_free(conf);
}
static void
test_section_mouse_bindings_collisions(void)
{
struct config conf = {0};
struct context ctx = {
.conf = &conf, .section = "mouse-bindings", .path = "unittest"};
test_binding_collisions(
&ctx,
BIND_ACTION_COUNT - 1, binding_action_map, MOUSE_BINDING);
config_free(conf);
}
int
main(int argc, const char *const *argv)
{
log_init(LOG_COLORIZE_AUTO, false, 0, LOG_CLASS_ERROR);
test_section_main();
test_section_bell();
test_section_scrollback();
test_section_key_bindings();
test_section_key_bindings_collisions();
test_section_search_bindings();
test_section_search_bindings_collisions();
test_section_url_bindings();
test_section_url_bindings_collisions();
test_section_mouse_bindings();
test_section_mouse_bindings_collisions();
log_deinit();
return 0;
}