#include <stic.h>

#include <unistd.h> /* chdir() rmdir() */

#include <stddef.h> /* NULL */
#include <stdlib.h> /* fclose() fopen() free() */
#include <string.h> /* strdup() strstr() */
#include <wchar.h> /* wcsdup() wcslen() */

#include <test-utils.h>

#include "../../src/compat/fs_limits.h"
#include "../../src/cfg/config.h"
#include "../../src/engine/abbrevs.h"
#include "../../src/engine/cmds.h"
#include "../../src/engine/completion.h"
#include "../../src/engine/functions.h"
#include "../../src/engine/options.h"
#include "../../src/engine/variables.h"
#include "../../src/int/path_env.h"
#include "../../src/lua/vlua.h"
#include "../../src/modes/cmdline.h"
#include "../../src/ui/ui.h"
#include "../../src/utils/env.h"
#include "../../src/utils/fs.h"
#include "../../src/utils/path.h"
#include "../../src/utils/str.h"
#include "../../src/bmarks.h"
#include "../../src/builtin_functions.h"
#include "../../src/cmd_core.h"
#include "../../src/plugins.h"
#include "../lua/asserts.h"

#define ASSERT_COMPLETION(initial, expected) \
	do \
	{ \
		prepare_for_line_completion(initial); \
		assert_success(line_completion(&stats)); \
		assert_wstring_equal(expected, stats.line); \
	} \
	while (0)

#define ASSERT_COMPLETION_ENDS_WITH(initial, expected) \
	do \
	{ \
		prepare_for_line_completion(initial); \
		assert_success(line_completion(&stats)); \
		assert_wstring_ends_with(expected, stats.line); \
	} \
	while (0)

#define ASSERT_NO_COMPLETION(initial) ASSERT_COMPLETION((initial), (initial))

#define ASSERT_NEXT_MATCH(str) \
	do \
	{ \
		char *const buf = vle_compl_next(); \
		assert_string_equal((str), buf); \
		free(buf); \
	} \
	while (0)

#define ASSERT_NEXT_MATCH_ENDS_WITH(str) \
	do \
	{ \
		char *const buf = vle_compl_next(); \
		assert_string_ends_with((str), buf); \
		free(buf); \
	} \
	while (0)

static void dummy_handler(OPT_OP op, optval_t val);
static void prepare_for_line_completion(const wchar_t str[]);

static line_stats_t stats;
static char *saved_cwd;

SETUP()
{
	static int option_changed;
	optval_t def = { .str_val = "/tmp" };

	cfg.slow_fs_list = strdup("");

	init_builtin_functions();

	stats.line = wcsdup(L"set ");
	stats.index = wcslen(stats.line);
	stats.curs_pos = 0;
	stats.len = stats.index;
	stats.cmd_pos = -1;
	stats.complete_continue = 0;
	stats.hist_search = 0;
	stats.hist_search_stash = NULL;
	stats.complete = &vle_cmds_complete;

	curr_view = &lwin;

	cmds_init();

	vle_opts_init(&option_changed, NULL);
	vle_opts_add("fusehome", "fh", "descr", OPT_STR, OPT_GLOBAL, 0, NULL,
			&dummy_handler, def);
	vle_opts_add("path", "pt", "descr", OPT_STR, OPT_GLOBAL, 0, NULL,
			&dummy_handler, def);
	vle_opts_add("path", "pt", "descr", OPT_STR, OPT_LOCAL, 0, NULL,
			&dummy_handler, def);

	saved_cwd = save_cwd();
	assert_success(chdir(TEST_DATA_PATH "/compare"));
	make_abs_path(curr_view->curr_dir, sizeof(curr_view->curr_dir),
			TEST_DATA_PATH, "compare", saved_cwd);

	curr_stats.cs = &cfg.cs;
}

TEARDOWN()
{
	cs_reset(&cfg.cs);
	curr_stats.cs = NULL;

	restore_cwd(saved_cwd);

	update_string(&cfg.slow_fs_list, NULL);

	free(stats.line);
	vle_opts_reset();

	function_reset_all();
}

TEST(test_set_completion)
{
	ASSERT_COMPLETION(L"set ", L"set all");
}

TEST(root_entries_are_completed)
{
	make_abs_path(curr_view->curr_dir, sizeof(curr_view->curr_dir),
			TEST_DATA_PATH, "", saved_cwd);
	assert_success(chdir(curr_view->curr_dir));

	prepare_for_line_completion(L"cd /");
	assert_success(line_completion(&stats));
	assert_true(wcscmp(L"cd /", stats.line) != 0);
}

TEST(dirs_are_completed_with_trailing_slash)
{
	make_abs_path(curr_view->curr_dir, sizeof(curr_view->curr_dir),
			TEST_DATA_PATH, "", saved_cwd);
	assert_success(chdir(curr_view->curr_dir));

	ASSERT_COMPLETION(L"cd r", L"cd read/");
	ASSERT_NEXT_MATCH("rename/");
	ASSERT_NEXT_MATCH("r");
	ASSERT_NEXT_MATCH("read/");
}

TEST(tabnew_has_directory_only_completion)
{
	make_abs_path(curr_view->curr_dir, sizeof(curr_view->curr_dir),
			TEST_DATA_PATH, "tree/dir1", saved_cwd);
	assert_success(chdir(curr_view->curr_dir));

	ASSERT_COMPLETION(L"tabnew ", L"tabnew dir2/");
	ASSERT_NEXT_MATCH("dir2/");
	ASSERT_NEXT_MATCH("dir2/");
}

TEST(function_name_completion)
{
	ASSERT_COMPLETION(L"echo e", L"echo escape(");
	ASSERT_NEXT_MATCH("executable(");
	ASSERT_NEXT_MATCH("expand(");
	ASSERT_NEXT_MATCH("extcached(");
	ASSERT_NEXT_MATCH("e");
}

TEST(abbreviations)
{
	vle_abbr_reset();
	assert_success(vle_abbr_add(L"lhs", L"rhs"));

	ASSERT_COMPLETION(L"cabbrev l", L"cabbrev lhs");
	ASSERT_COMPLETION(L"cnoreabbrev l", L"cnoreabbrev lhs");
	ASSERT_COMPLETION(L"cunabbrev l", L"cunabbrev lhs");
	ASSERT_NO_COMPLETION(L"cabbrev l l");

	vle_abbr_reset();
}

TEST(bang_exec_completion)
{
	char *const original_path_env = strdup(env_get("PATH"));

	restore_cwd(saved_cwd);
	assert_success(chdir(SANDBOX_PATH));
	saved_cwd = save_cwd();

	env_set("PATH", saved_cwd);
	update_path_env(1);

	create_executable("exec-for-completion" EXE_SUFFIX);

	ASSERT_COMPLETION(L"!exec-for-com", L"!exec-for-completion" EXE_SUFFIXW);

	assert_success(unlink("exec-for-completion" EXE_SUFFIX));

	env_set("PATH", original_path_env);
	update_path_env(1);
	free(original_path_env);
}

TEST(bang_abs_path_completion)
{
	wchar_t input[PATH_MAX + 1];
	wchar_t cmd[PATH_MAX + 1];
	char cwd[PATH_MAX + 1];
	wchar_t *wcwd;

	restore_cwd(saved_cwd);
	saved_cwd = save_cwd();
	assert_success(chdir(SANDBOX_PATH));

	assert_true(get_cwd(cwd, sizeof(cwd)) == cwd);
	wcwd = to_wide(cwd);

	create_executable("exec-for-completion" EXE_SUFFIX);

	vifm_swprintf(input, ARRAY_LEN(input),
			L"!%" WPRINTF_WSTR L"/exec-for-compl", wcwd);
	vifm_swprintf(cmd, ARRAY_LEN(cmd),
			L"!%" WPRINTF_WSTR L"/exec-for-completion" EXE_SUFFIXW, wcwd);

	ASSERT_COMPLETION(input, cmd);

	assert_int_equal(2, vle_compl_get_count());

	assert_success(unlink("exec-for-completion" EXE_SUFFIX));

	free(wcwd);
}

TEST(standalone_tilde_is_expanded)
{
	make_abs_path(cfg.home_dir, sizeof(cfg.home_dir), TEST_DATA_PATH, "/",
			saved_cwd);

	char *expected = format_str("cd %s", cfg.home_dir);
	wchar_t *wexpected = to_wide(expected);

	ASSERT_COMPLETION(L"cd ~", wexpected);

	free(wexpected);
	free(expected);
}

TEST(tilde_is_completed_after_emark)
{
	make_abs_path(cfg.home_dir, sizeof(cfg.home_dir), TEST_DATA_PATH, "/",
			saved_cwd);
	ASSERT_COMPLETION(L"!~/", L"!~/color-schemes/");
}

TEST(user_name_is_completed_after_tilde, IF(not_windows))
{
	prepare_for_line_completion(L"cd ~roo");
	assert_success(line_completion(&stats));
	char *narrow = to_multibyte(stats.line);
	assert_string_equal(NULL, strstr(narrow, "\\~"));
	free(narrow);
}

TEST(bmark_tags_are_completed)
{
	bmarks_clear();

	assert_success(cmds_dispatch("bmark! fake/path1 tag1", &lwin, CIT_COMMAND));

	ASSERT_COMPLETION(L"bmark tag", L"bmark tag1");
	ASSERT_COMPLETION(L"bmark! fake/path2 tag", L"bmark! fake/path2 tag1");
	ASSERT_NO_COMPLETION(L"bmark! fake/path2 ../");
	ASSERT_COMPLETION(L"bmark! fake/path2 ", L"bmark! fake/path2 tag1");

	/* Current tag is added to the list of completions unless it's a duplicate. */
	ASSERT_COMPLETION(L"bmark tag1", L"bmark tag1");
	assert_int_equal(2, vle_compl_get_count());
	ASSERT_COMPLETION(L"bmark tag1 tag1", L"bmark tag1 tag1");
	assert_int_equal(1, vle_compl_get_count());
}

TEST(bmark_path_is_completed)
{
	bmarks_clear();

	make_abs_path(curr_view->curr_dir, sizeof(curr_view->curr_dir), SANDBOX_PATH,
			"", saved_cwd);
	assert_success(chdir(curr_view->curr_dir));
	create_executable("exec-for-completion" EXE_SUFFIX);

	ASSERT_COMPLETION(L"bmark! exec", L"bmark! exec-for-completion" EXE_SUFFIX);

	assert_success(unlink("exec-for-completion" EXE_SUFFIX));
}

TEST(delbmark_tags_are_completed)
{
	bmarks_clear();

	assert_success(cmds_dispatch("bmark! fake/path1 tag1", &lwin, CIT_COMMAND));

	ASSERT_COMPLETION(L"delbmark ta", L"delbmark tag1");
}

TEST(selective_sync_completion)
{
	ASSERT_COMPLETION(L"sync! a", L"sync! all");
	ASSERT_NO_COMPLETION(L"sync! ../");
}

TEST(colorscheme_completion)
{
	make_abs_path(cfg.colors_dir, sizeof(cfg.colors_dir), TEST_DATA_PATH,
			"scripts", saved_cwd);
	ASSERT_COMPLETION(L"colorscheme set-", L"colorscheme set-env");
	ASSERT_COMPLETION(L"colorscheme set-env ../",
			L"colorscheme set-env ../color-schemes/");
	ASSERT_NO_COMPLETION(L"colorscheme ../");

	make_abs_path(curr_view->curr_dir, sizeof(curr_view->curr_dir),
			TEST_DATA_PATH, "", saved_cwd);
	ASSERT_COMPLETION(L"colorscheme set-env ",
			L"colorscheme set-env color-schemes/");
}

TEST(wincmd_completion)
{
	ASSERT_COMPLETION(L"wincmd ", L"wincmd +");
	ASSERT_NO_COMPLETION(L"wincmd + ");
}

TEST(grep_completion)
{
	ASSERT_NO_COMPLETION(L"grep -");
	ASSERT_NO_COMPLETION(L"grep .");
	ASSERT_COMPLETION(L"grep -o ..", L"grep -o ../");

	make_abs_path(curr_view->curr_dir, sizeof(curr_view->curr_dir),
			TEST_DATA_PATH, "", saved_cwd);
	assert_success(chdir(curr_view->curr_dir));

	ASSERT_COMPLETION(L"grep -o ", L"grep -o color-schemes/");
}

TEST(find_completion)
{
#ifdef _WIN32
	/* Windows escaping code doesn't prepend "./". */
	ASSERT_NO_COMPLETION(L"find -");
#else
	ASSERT_COMPLETION(L"find -", L"find ./-");
#endif

	ASSERT_COMPLETION(L"find ..", L"find ../");
	ASSERT_NO_COMPLETION(L"find . .");

	make_abs_path(curr_view->curr_dir, sizeof(curr_view->curr_dir),
			TEST_DATA_PATH, "", saved_cwd);
	assert_success(chdir(curr_view->curr_dir));

	ASSERT_COMPLETION(L"find ", L"find color-schemes/");
}

TEST(aucmd_events_are_completed)
{
	ASSERT_COMPLETION(L"autocmd ", L"autocmd DirEnter");
	ASSERT_COMPLETION(L"autocmd Dir", L"autocmd DirEnter");
	ASSERT_COMPLETION(L"autocmd! Dir", L"autocmd! DirEnter");
	ASSERT_NO_COMPLETION(L"autocmd DirEnter ");
}

TEST(prefixless_option_name_is_completed)
{
	ASSERT_COMPLETION(L"echo &", L"echo &fusehome");
	assert_success(line_completion(&stats));
	assert_wstring_equal(L"echo &path", stats.line);
}

TEST(prefixed_global_option_name_is_completed)
{
	ASSERT_COMPLETION(L"echo &g:f", L"echo &g:fusehome");
}

TEST(prefixed_local_option_name_is_completed)
{
	ASSERT_COMPLETION(L"echo &l:p", L"echo &l:path");
}

TEST(autocmd_name_completion_is_case_insensitive)
{
	ASSERT_COMPLETION(L"autocmd dir", L"autocmd DirEnter");
}

TEST(case_override_of_paths)
{
	make_abs_path(curr_view->curr_dir, sizeof(curr_view->curr_dir),
			TEST_DATA_PATH, "existing-files", saved_cwd);
	assert_success(chdir(curr_view->curr_dir));

	cfg.ignore_case = 0;
	cfg.case_override = CO_PATH_COMPL;
	cfg.case_ignore = CO_PATH_COMPL;

	ASSERT_COMPLETION(L"edit A", L"edit a");

	cfg.case_override = 0;
	cfg.case_ignore = 0;
}

TEST(envvars_are_completed_for_edit)
{
	env_set("RRRRRARE_VARIABLE1", "1");
	env_set("RRRRRARE_VARIABLE2", "2");

	ASSERT_COMPLETION(L"edit $RRRRRARE_VARIA", L"edit $RRRRRARE_VARIABLE1");
}

TEST(builtinvars_are_completed_for_echo)
{
	init_variables();
	assert_success(setvar("v:test", var_from_bool(1)));
	ASSERT_COMPLETION(L"echo v:t", L"echo v:test");
	clear_variables();
}

TEST(select_is_completed)
{
	env_set("RRRRRARE_VARIABLE1", "1");
	env_set("RRRRRARE_VARIABLE2", "2");

	ASSERT_NO_COMPLETION(L"select $RRRRRARE_VARIA");
	ASSERT_NO_COMPLETION(L"select !/$RRRRRARE_VARIA");
	ASSERT_NO_COMPLETION(L"select !cmd some-arg");

	/* Check that not memory violations occur here. */
	prepare_for_line_completion(L"select !cmd ");
	assert_success(line_completion(&stats));

	ASSERT_COMPLETION(L"select!!$RRRRRARE_VARIA", L"select!!$RRRRRARE_VARIABLE1");
	ASSERT_COMPLETION(L"unselect !cat $RRRRRARE_VARIA",
			L"unselect !cat $RRRRRARE_VARIABLE1");
}

TEST(compare_is_completed)
{
	ASSERT_COMPLETION(L"compare by", L"compare bycontents");
	ASSERT_COMPLETION(L"compare bysize list", L"compare bysize listall");
}

TEST(symlinks_in_paths_are_not_resolved, IF(not_windows))
{
	restore_cwd(saved_cwd);
	saved_cwd = save_cwd();

	char src[PATH_MAX + 1], dst[PATH_MAX + 1];
	make_abs_path(src, sizeof(src), TEST_DATA_PATH, "compare", saved_cwd);
	make_abs_path(dst, sizeof(dst), SANDBOX_PATH, "dir-link", saved_cwd);
	assert_success(make_symlink(src, dst));

	assert_success(chdir(SANDBOX_PATH "/dir-link"));
	make_abs_path(curr_view->curr_dir, sizeof(curr_view->curr_dir), SANDBOX_PATH,
			"dir-link", saved_cwd);

	ASSERT_COMPLETION(L"cd ../d", L"cd ../dir-link/");

	restore_cwd(saved_cwd);
	saved_cwd = save_cwd();
	assert_success(remove(SANDBOX_PATH "/dir-link"));
}

TEST(session_is_completed)
{
	restore_cwd(saved_cwd);
	saved_cwd = save_cwd();

	make_abs_path(cfg.config_dir, sizeof(cfg.config_dir), SANDBOX_PATH, "",
			saved_cwd);

	create_dir(SANDBOX_PATH "/sessions");
	create_dir(SANDBOX_PATH "/sessions/subdir.json");
	create_file(SANDBOX_PATH "/sessions/subdir.json/file.json");
	create_file(SANDBOX_PATH "/sessions/session-a.json");
	create_file(SANDBOX_PATH "/sessions/session-b.json");

	ASSERT_COMPLETION(L"session ", L"session session-a");
	ASSERT_NEXT_MATCH("session-b");
	ASSERT_NEXT_MATCH("");

	ASSERT_NO_COMPLETION(L"session session-a ..");

	ASSERT_NO_COMPLETION(L"session! ses");
	ASSERT_NO_COMPLETION(L"session? ses");

	remove_file(SANDBOX_PATH "/sessions/session-b.json");
	remove_file(SANDBOX_PATH "/sessions/session-a.json");
	remove_file(SANDBOX_PATH "/sessions/subdir.json/file.json");
	remove_dir(SANDBOX_PATH "/sessions/subdir.json");
	remove_dir(SANDBOX_PATH "/sessions");

	cfg.config_dir[0] = '\0';
}

TEST(delsession_is_completed)
{
	restore_cwd(saved_cwd);
	saved_cwd = save_cwd();

	make_abs_path(cfg.config_dir, sizeof(cfg.config_dir), SANDBOX_PATH, "",
			saved_cwd);

	create_dir(SANDBOX_PATH "/sessions");
	create_dir(SANDBOX_PATH "/sessions/subdir.json");
	create_file(SANDBOX_PATH "/sessions/subdir.json/file.json");
	create_file(SANDBOX_PATH "/sessions/session-a.json");
	create_file(SANDBOX_PATH "/sessions/session-b.json");

	ASSERT_COMPLETION(L"delsession ", L"delsession session-a");
	ASSERT_NEXT_MATCH("session-b");
	ASSERT_NEXT_MATCH("");

	ASSERT_NO_COMPLETION(L"delsession session-a ..");

	ASSERT_NO_COMPLETION(L"delsession! ses");
	ASSERT_NO_COMPLETION(L"delsession? ses");

	remove_file(SANDBOX_PATH "/sessions/session-b.json");
	remove_file(SANDBOX_PATH "/sessions/session-a.json");
	remove_file(SANDBOX_PATH "/sessions/subdir.json/file.json");
	remove_dir(SANDBOX_PATH "/sessions/subdir.json");
	remove_dir(SANDBOX_PATH "/sessions");

	cfg.config_dir[0] = '\0';
}

TEST(plugin_is_completed)
{
	ASSERT_COMPLETION(L"plugin ", L"plugin blacklist");
	ASSERT_NEXT_MATCH("load");
	ASSERT_NEXT_MATCH("whitelist");
	ASSERT_NEXT_MATCH("");

	ASSERT_COMPLETION(L"plugin w", L"plugin whitelist");
	ASSERT_NEXT_MATCH("whitelist");

	restore_cwd(saved_cwd);
	saved_cwd = save_cwd();

	make_abs_path(cfg.config_dir, sizeof(cfg.config_dir), SANDBOX_PATH, "", NULL);
	create_dir(SANDBOX_PATH "/plugins");
	create_dir(SANDBOX_PATH "/plugins/plug1");
	create_dir(SANDBOX_PATH "/plugins/plug2");
	make_file(SANDBOX_PATH "/plugins/plug1/init.lua", "return {}");
	make_file(SANDBOX_PATH "/plugins/plug2/init.lua", "return");

	curr_stats.vlua = vlua_init();
	curr_stats.plugs = plugs_create(curr_stats.vlua);
	load_plugins(curr_stats.plugs, cfg.config_dir);

	ASSERT_COMPLETION(L"plugin whitelist ", L"plugin whitelist plug1");
	ASSERT_NEXT_MATCH("plug2");
	ASSERT_NEXT_MATCH("");

	plugs_free(curr_stats.plugs);
	vlua_finish(curr_stats.vlua);
	curr_stats.plugs = NULL;
	curr_stats.vlua = NULL;

	remove_file(SANDBOX_PATH "/plugins/plug1/init.lua");
	remove_file(SANDBOX_PATH "/plugins/plug2/init.lua");
	remove_dir(SANDBOX_PATH "/plugins/plug1");
	remove_dir(SANDBOX_PATH "/plugins/plug2");
	remove_dir(SANDBOX_PATH "/plugins");
}

TEST(tree_is_completed)
{
	prepare_for_line_completion(L"tree ");

	assert_success(line_completion(&stats));
	assert_wstring_equal(L"tree depth=", stats.line);
}

TEST(highlight_is_completed)
{
	ASSERT_COMPLETION(L"hi ", L"hi AuxWin");
	ASSERT_COMPLETION(L"hi wi", L"hi WildBox");
	ASSERT_COMPLETION(L"hi WildMenu cter", L"hi WildMenu cterm");

	ASSERT_COMPLETION(L"hi WildMenu ctermfg=def", L"hi WildMenu ctermfg=default");
	ASSERT_COMPLETION(L"hi WildMenu ctermfg=no", L"hi WildMenu ctermfg=none");
	ASSERT_COMPLETION(L"hi WildMenu ctermfg=r", L"hi WildMenu ctermfg=Red1");
	ASSERT_COMPLETION(L"hi WildMenu ctermfg=lightb",
			L"hi WildMenu ctermfg=lightblack");
	ASSERT_COMPLETION(L"hi WildMenu cterm=re", L"hi WildMenu cterm=reverse");
	ASSERT_COMPLETION(L"hi WildMenu cterm=bold,re",
			L"hi WildMenu cterm=bold,reverse");

	ASSERT_COMPLETION(L"hi WildMenu guibg=r", L"hi WildMenu guibg=red");
	ASSERT_COMPLETION(L"hi WildMenu guibg=l", L"hi WildMenu guibg=l");

	assert_success(cmds_dispatch("hi {*.jpg} cterm=none", &lwin, CIT_COMMAND));
	ASSERT_COMPLETION(L"hi clear ", L"hi clear {*.jpg}");
}

TEST(highlight_columns_are_completed)
{
	curr_stats.vlua = vlua_init();

	GLUA_EQ(curr_stats.vlua, "", "function handler() end");
	GLUA_EQ(curr_stats.vlua, "",
			"vifm.addcolumntype{ name = 'Test', handler = handler }");

	/* Completion doesn't require columns to be colored. */
	ASSERT_COMPLETION(L"hi column:s", L"hi column:size");
	ASSERT_COMPLETION(L"hi column:T", L"hi column:Test");

	assert_success(cmds_dispatch("hi column:size cterm=bold", &lwin, CIT_COMMAND));
	ASSERT_COMPLETION(L"hi clear column:si", L"hi clear column:size");

	vlua_finish(curr_stats.vlua);
	curr_stats.vlua = NULL;
}

TEST(command_options_are_completed)
{
	ASSERT_COMPLETION(L"copy -", L"copy -skip");

	other_view = &rwin;
#ifndef _WIN32
	ASSERT_COMPLETION(L"copy -- -", L"copy -- ./-");
#else
	ASSERT_COMPLETION(L"copy -- -", L"copy -- -");
#endif
	other_view = NULL;
}

TEST(wingo_is_completed)
{
	make_abs_path(lwin.curr_dir, sizeof(lwin.curr_dir), TEST_DATA_PATH,
			"compare/a", saved_cwd);
	make_abs_path(rwin.curr_dir, sizeof(rwin.curr_dir), TEST_DATA_PATH,
			"compare/b", saved_cwd);

	ASSERT_COMPLETION_ENDS_WITH(L"wingo ", L"/compare/a");
	ASSERT_NEXT_MATCH_ENDS_WITH("/compare/b");

	/* Check that path part designed by ~ is being matched against. */
	cfg.shorten_title_paths = 1;
	make_abs_path(cfg.home_dir, sizeof(cfg.home_dir), TEST_DATA_PATH,
			"/compare/b/", saved_cwd);
	ASSERT_COMPLETION_ENDS_WITH(L"wingo compare/b", L" ~");
	cfg.shorten_title_paths = 0;
}

static void
dummy_handler(OPT_OP op, optval_t val)
{
	ASSERT_NO_COMPLETION(L"nosuchcommand a");
}

static void
prepare_for_line_completion(const wchar_t str[])
{
	free(stats.line);
	stats.line = wcsdup(str);
	stats.len = wcslen(stats.line);
	stats.index = stats.len;
	stats.complete_continue = 0;

	vle_compl_reset();
}

/* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
/* vim: set cinoptions+=t0 filetype=c : */
