1 #include <stic.h>
2 
3 #include <sys/time.h> /* timeval utimes() */
4 #include <unistd.h> /* rmdir() symlink() */
5 
6 #include <stddef.h> /* NULL */
7 #include <stdlib.h> /* free() remove() */
8 #include <string.h> /* strdup() */
9 
10 #include <test-utils.h>
11 
12 #include "../../src/cfg/config.h"
13 #include "../../src/compat/fs_limits.h"
14 #include "../../src/compat/os.h"
15 #include "../../src/engine/functions.h"
16 #include "../../src/engine/parsing.h"
17 #include "../../src/engine/variables.h"
18 #include "../../src/utils/env.h"
19 #include "../../src/utils/fs.h"
20 #include "../../src/utils/str.h"
21 #include "../../src/args.h"
22 #include "../../src/builtin_functions.h"
23 #include "../../src/compare.h"
24 #include "../../src/filelist.h"
25 #include "../../src/status.h"
26 #include "../parsing/asserts.h"
27 
SETUP()28 SETUP()
29 {
30 	update_string(&cfg.shell, "sh");
31 	update_string(&cfg.shell_cmd_flag, "-c");
32 
33 	init_builtin_functions();
34 	init_parser(NULL);
35 	init_variables();
36 
37 	view_setup(&lwin);
38 
39 	assert_non_null(get_cwd(lwin.curr_dir, sizeof(lwin.curr_dir)));
40 }
41 
TEARDOWN()42 TEARDOWN()
43 {
44 	clear_envvars();
45 	function_reset_all();
46 	update_string(&cfg.shell, NULL);
47 	update_string(&cfg.shell_cmd_flag, NULL);
48 
49 	view_teardown(&lwin);
50 }
51 
TEST(executable_true_for_executable)52 TEST(executable_true_for_executable)
53 {
54 	const char *const exec_file = SANDBOX_PATH "/exec-for-completion" EXE_SUFFIX;
55 
56 	create_executable(exec_file);
57 
58 	ASSERT_INT_OK(
59 			"executable('" SANDBOX_PATH "/exec-for-completion" EXE_SUFFIX "')", 1);
60 
61 	assert_success(remove(exec_file));
62 }
63 
TEST(executable_false_for_regular_file)64 TEST(executable_false_for_regular_file)
65 {
66 	ASSERT_INT_OK("executable('Makefile')", 0);
67 }
68 
TEST(executable_false_for_dir)69 TEST(executable_false_for_dir)
70 {
71 	ASSERT_INT_OK("executable('.')", 0);
72 }
73 
TEST(expand_expands_environment_variables)74 TEST(expand_expands_environment_variables)
75 {
76 	let_variables("$OPEN_ME = 'Found something interesting?'");
77 	ASSERT_OK("expand('$OPEN_ME')", "Found something interesting?");
78 }
79 
TEST(system_catches_stdout)80 TEST(system_catches_stdout)
81 {
82 	ASSERT_OK("system('echo a')", "a");
83 }
84 
TEST(system_catches_stderr)85 TEST(system_catches_stderr)
86 {
87 #ifndef _WIN32
88 	ASSERT_OK("system('echo a 1>&2')", "a");
89 #else
90 	/* "echo" implemented by cmd.exe is kinda disabled, and doesn't ignore
91 	 * spaces. */
92 	ASSERT_OK("system('echo a 1>&2')", "a ");
93 #endif
94 }
95 
TEST(system_catches_stdout_and_err)96 TEST(system_catches_stdout_and_err)
97 {
98 #ifndef _WIN32
99 	ASSERT_OK("system('echo a && echo b 1>&2')", "a\nb");
100 #else
101 	/* "echo" implemented by cmd.exe is kinda disabled, and doesn't ignore
102 	 * spaces. */
103 	ASSERT_OK("system('echo a && echo b 1>&2')", "a \nb ");
104 #endif
105 }
106 
TEST(term_catches_stdout)107 TEST(term_catches_stdout)
108 {
109 	ASSERT_OK("term('echo a')", "a");
110 }
111 
TEST(layoutis_is_correct_for_single_pane)112 TEST(layoutis_is_correct_for_single_pane)
113 {
114 	curr_stats.number_of_windows = 1;
115 	curr_stats.split = VSPLIT;
116 	curr_stats.split = HSPLIT;
117 	ASSERT_OK("layoutis('only')", "1");
118 	ASSERT_OK("layoutis('split')", "0");
119 	ASSERT_OK("layoutis('hsplit')", "0");
120 	ASSERT_OK("layoutis('vsplit')", "0");
121 }
122 
TEST(layoutis_is_correct_for_hsplit)123 TEST(layoutis_is_correct_for_hsplit)
124 {
125 	curr_stats.number_of_windows = 2;
126 	curr_stats.split = HSPLIT;
127 	ASSERT_OK("layoutis('only')", "0");
128 	ASSERT_OK("layoutis('split')", "1");
129 	ASSERT_OK("layoutis('hsplit')", "1");
130 	ASSERT_OK("layoutis('vsplit')", "0");
131 }
132 
TEST(layoutis_is_correct_for_vsplit)133 TEST(layoutis_is_correct_for_vsplit)
134 {
135 	curr_stats.number_of_windows = 2;
136 	curr_stats.split = VSPLIT;
137 	ASSERT_OK("layoutis('only')", "0");
138 	ASSERT_OK("layoutis('split')", "1");
139 	ASSERT_OK("layoutis('hsplit')", "0");
140 	ASSERT_OK("layoutis('vsplit')", "1");
141 }
142 
TEST(paneisat_is_correct_for_single_pane)143 TEST(paneisat_is_correct_for_single_pane)
144 {
145 	curr_stats.number_of_windows = 1;
146 	curr_stats.split = VSPLIT;
147 	curr_stats.split = HSPLIT;
148 	ASSERT_OK("paneisat('top')", "1");
149 	ASSERT_OK("paneisat('bottom')", "1");
150 	ASSERT_OK("paneisat('left')", "1");
151 	ASSERT_OK("paneisat('right')", "1");
152 }
153 
TEST(paneisat_is_correct_for_hsplit)154 TEST(paneisat_is_correct_for_hsplit)
155 {
156 	curr_stats.number_of_windows = 2;
157 	curr_stats.split = HSPLIT;
158 
159 	curr_view = &lwin;
160 	ASSERT_OK("paneisat('top')", "1");
161 	ASSERT_OK("paneisat('bottom')", "0");
162 	ASSERT_OK("paneisat('left')", "1");
163 	ASSERT_OK("paneisat('right')", "1");
164 
165 	curr_view = &rwin;
166 	ASSERT_OK("paneisat('top')", "0");
167 	ASSERT_OK("paneisat('bottom')", "1");
168 	ASSERT_OK("paneisat('left')", "1");
169 	ASSERT_OK("paneisat('right')", "1");
170 }
171 
TEST(paneisat_is_correct_for_vsplit)172 TEST(paneisat_is_correct_for_vsplit)
173 {
174 	curr_stats.number_of_windows = 2;
175 	curr_stats.split = VSPLIT;
176 
177 	curr_view = &lwin;
178 	ASSERT_OK("paneisat('top')", "1");
179 	ASSERT_OK("paneisat('bottom')", "1");
180 	ASSERT_OK("paneisat('left')", "1");
181 	ASSERT_OK("paneisat('right')", "0");
182 
183 	curr_view = &rwin;
184 	ASSERT_OK("paneisat('top')", "1");
185 	ASSERT_OK("paneisat('bottom')", "1");
186 	ASSERT_OK("paneisat('left')", "0");
187 	ASSERT_OK("paneisat('right')", "1");
188 }
189 
TEST(getpanetype_for_regular_view)190 TEST(getpanetype_for_regular_view)
191 {
192 	curr_view = &lwin;
193 	ASSERT_OK("getpanetype()", "regular");
194 }
195 
TEST(getpanetype_for_custom_view)196 TEST(getpanetype_for_custom_view)
197 {
198 	flist_custom_start(&lwin, "test");
199 	flist_custom_add(&lwin, TEST_DATA_PATH "/existing-files/a");
200 	assert_true(flist_custom_finish(&lwin, CV_REGULAR, 0) == 0);
201 
202 	curr_view = &lwin;
203 	ASSERT_OK("getpanetype()", "custom");
204 }
205 
TEST(getpanetype_for_very_custom_view)206 TEST(getpanetype_for_very_custom_view)
207 {
208 	opt_handlers_setup();
209 
210 	flist_custom_start(&lwin, "test");
211 	flist_custom_add(&lwin, TEST_DATA_PATH "/existing-files/a");
212 	assert_true(flist_custom_finish(&lwin, CV_VERY, 0) == 0);
213 
214 	curr_view = &lwin;
215 	ASSERT_OK("getpanetype()", "very-custom");
216 
217 	opt_handlers_teardown();
218 }
219 
TEST(getpanetype_for_tree_view)220 TEST(getpanetype_for_tree_view)
221 {
222 	flist_load_tree(&lwin, TEST_DATA_PATH);
223 
224 	curr_view = &lwin;
225 	ASSERT_OK("getpanetype()", "tree");
226 }
227 
TEST(getpanetype_for_compare_view)228 TEST(getpanetype_for_compare_view)
229 {
230 	strcpy(lwin.curr_dir, TEST_DATA_PATH "/rename");
231 
232 	curr_view = &lwin;
233 	other_view = &rwin;
234 
235 	opt_handlers_setup();
236 	compare_one_pane(&lwin, CT_CONTENTS, LT_DUPS, 0);
237 	opt_handlers_teardown();
238 
239 	ASSERT_OK("getpanetype()", "compare");
240 }
241 
TEST(chooseopt_options_are_not_set)242 TEST(chooseopt_options_are_not_set)
243 {
244 	args_t args = { };
245 	char *argv[] = { "vifm", NULL };
246 
247 	assert_success(stats_init(&cfg));
248 
249 	args_parse(&args, ARRAY_LEN(argv) - 1U, argv, "/");
250 	args_process(&args, 0);
251 	args_process(&args, 1);
252 
253 	ASSERT_OK("chooseopt('files')", "");
254 	ASSERT_OK("chooseopt('dir')", "");
255 	ASSERT_OK("chooseopt('cmd')", "");
256 	ASSERT_OK("chooseopt('delimiter')", "\n");
257 
258 	assert_success(stats_reset(&cfg));
259 
260 	args_free(&args);
261 }
262 
TEST(chooseopt_options_are_set)263 TEST(chooseopt_options_are_set)
264 {
265 	args_t args = { };
266 	char *argv[] = { "vifm",
267 	                 "--choose-files", "files-file",
268 	                 "--choose-dir", "dir-file",
269 	                 "--on-choose", "cmd",
270 	                 "--delimiter", "delim",
271 	                 NULL };
272 
273 	assert_success(stats_init(&cfg));
274 
275 	args_parse(&args, ARRAY_LEN(argv) - 1U, argv, "/");
276 	args_process(&args, 0);
277 	args_process(&args, 1);
278 
279 	ASSERT_OK("chooseopt('files')", "/files-file");
280 	ASSERT_OK("chooseopt('dir')", "/dir-file");
281 	ASSERT_OK("chooseopt('cmd')", "cmd");
282 	ASSERT_OK("chooseopt('delimiter')", "delim");
283 
284 	assert_success(stats_reset(&cfg));
285 
286 	args_free(&args);
287 }
288 
TEST(tabpagenr)289 TEST(tabpagenr)
290 {
291 	ASSERT_OK("tabpagenr()", "1");
292 	ASSERT_OK("tabpagenr('$')", "1");
293 
294 	ASSERT_FAIL("tabpagenr(1)", PE_INVALID_EXPRESSION);
295 	ASSERT_FAIL("tabpagenr('a')", PE_INVALID_EXPRESSION);
296 }
297 
TEST(fnameescape)298 TEST(fnameescape)
299 {
300 	ASSERT_FAIL("fnameescape()", PE_INVALID_EXPRESSION);
301 
302 	ASSERT_OK("fnameescape(' ')", "\\ ");
303 	ASSERT_OK("fnameescape('%')", "%%");
304 	ASSERT_OK("fnameescape(\"'\")", "\\'");
305 	ASSERT_OK("fnameescape('\"')", "\\\"");
306 }
307 
TEST(filetype)308 TEST(filetype)
309 {
310 	opt_handlers_setup();
311 
312 	/* symlink() is not available on Windows, but the rest of the code is fine. */
313 #ifndef _WIN32
314 	char cwd[PATH_MAX + 1];
315 	assert_non_null(get_cwd(cwd, sizeof(cwd)));
316 	char test_data[PATH_MAX + 1];
317 	make_abs_path(test_data, sizeof(test_data), TEST_DATA_PATH, "", cwd);
318 
319 	char path[PATH_MAX + 1];
320 	snprintf(path, sizeof(path), "%s/existing-files", test_data);
321 	assert_success(symlink(path, SANDBOX_PATH "/dir-link"));
322 	snprintf(path, sizeof(path), "%s/existing-files/b", test_data);
323 	assert_success(symlink(path, SANDBOX_PATH "/file-link"));
324 	snprintf(path, sizeof(path), "%s/no-such-file", test_data);
325 	assert_success(symlink(path, SANDBOX_PATH "/broken-link"));
326 #endif
327 
328 	flist_custom_start(&lwin, "test");
329 	flist_custom_add(&lwin, TEST_DATA_PATH "/existing-files/a");
330 	flist_custom_add(&lwin, TEST_DATA_PATH "/compare");
331 #ifndef _WIN32
332 	flist_custom_add(&lwin, SANDBOX_PATH "/dir-link");
333 	flist_custom_add(&lwin, SANDBOX_PATH "/file-link");
334 	flist_custom_add(&lwin, SANDBOX_PATH "/broken-link");
335 #endif
336 	assert_true(flist_custom_finish(&lwin, CV_VERY, 0) == 0);
337 
338 	curr_view = &lwin;
339 
340 	ASSERT_OK("filetype('')", "");
341 	lwin.list_pos = 0;
342 	ASSERT_OK("filetype('.')", "reg");
343 	ASSERT_OK("filetype(1)", "reg");
344 	ASSERT_OK("filetype(2)", "dir");
345 #ifndef _WIN32
346 	ASSERT_OK("filetype('3')", "link");
347 	ASSERT_OK("filetype('4')", "link");
348 	ASSERT_OK("filetype('3', 1)", "dir");
349 	ASSERT_OK("filetype('4', 1)", "reg");
350 	ASSERT_OK("filetype(5, 1)", "broken");
351 #endif
352 
353 	opt_handlers_teardown();
354 
355 #ifndef _WIN32
356 	assert_success(remove(SANDBOX_PATH "/dir-link"));
357 	assert_success(remove(SANDBOX_PATH "/file-link"));
358 	assert_success(remove(SANDBOX_PATH "/broken-link"));
359 #endif
360 }
361 
TEST(has)362 TEST(has)
363 {
364 #ifndef _WIN32
365 	ASSERT_OK("has('unix')", "1");
366 	ASSERT_OK("has('win')", "0");
367 #else
368 	ASSERT_OK("has('unix')", "0");
369 	ASSERT_OK("has('win')", "1");
370 #endif
371 
372 	ASSERT_OK("has('anythingelse')", "0");
373 	ASSERT_OK("has('nix')", "0");
374 	ASSERT_OK("has('windows')", "0");
375 }
376 
TEST(extcached)377 TEST(extcached)
378 {
379 	/* Testing with FMT_CHANGED is problematic, because change time is not
380 	 * programmatically accessible for writing. */
381 	set_extcached_monitor_type(FMT_MODIFIED);
382 
383 	create_file("file");
384 	assert_success(os_mkdir("dir", 0700));
385 
386 	/* For directories. */
387 	ASSERT_OK("extcached('cache1', 'dir', 'echo 1')", "1");
388 	/* Unchanged. */
389 	ASSERT_OK("extcached('cache1', 'dir', 'echo 2')", "1");
390 #ifndef _WIN32
391 	/* Changed. */
392 	struct timeval tvs[2] = {};
393 	assert_success(utimes("dir", tvs));
394 	ASSERT_OK("extcached('cache1', 'dir', 'echo 3')", "3");
395 	/* Unchanged again. */
396 	ASSERT_OK("extcached('cache1', 'dir', 'echo 4')", "3");
397 #endif
398 
399 	/* For files. */
400 	ASSERT_OK("extcached('cache1', 'file', 'echo 5')", "5");
401 	/* Unchanged. */
402 	ASSERT_OK("extcached('cache1', 'file', 'echo 6')", "5");
403 #ifndef _WIN32
404 	/* Changed. */
405 	assert_success(utimes("file", tvs));
406 	ASSERT_OK("extcached('cache1', 'file', 'echo 7')", "7");
407 	/* Unchanged again. */
408 	ASSERT_OK("extcached('cache1', 'file', 'echo 8')", "7");
409 #endif
410 
411 	/* Caches don't mix. */
412 	ASSERT_OK("extcached('cache2', 'dir', 'echo a')", "a");
413 	ASSERT_OK("extcached('cache3', 'dir', 'echo b')", "b");
414 
415 #ifndef _WIN32
416 	/* Change resets all caches. */
417 	tvs[0].tv_sec = 1;
418 	tvs[1].tv_sec = 1;
419 	assert_success(utimes("dir", tvs));
420 	ASSERT_OK("extcached('cache1', 'dir', 'echo 00')", "00");
421 	ASSERT_OK("extcached('cache2', 'dir', 'echo aa')", "aa");
422 	ASSERT_OK("extcached('cache3', 'dir', 'echo bb')", "bb");
423 #endif
424 
425 	assert_success(remove("file"));
426 	assert_success(rmdir("dir"));
427 
428 	set_extcached_monitor_type(FMT_CHANGED);
429 }
430 
431 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
432 /* vim: set cinoptions+=t0 filetype=c : */
433