1 #include "test-utils.h"
2 
3 #include <stic.h>
4 
5 #include <sys/stat.h> /* chmod() */
6 #include <sys/time.h> /* timeval utimes() */
7 #include <unistd.h> /* access() rmdir() usleep() */
8 
9 #ifdef _WIN32
10 #include <windows.h>
11 #endif
12 
13 #include <locale.h> /* LC_ALL setlocale() */
14 #include <stddef.h> /* NULL */
15 #include <stdio.h> /* FILE fclose() fopen() fread() remove() */
16 #include <stdlib.h> /* free() */
17 #include <string.h> /* memset() strcpy() strdup() */
18 
19 #include "../../src/cfg/config.h"
20 #include "../../src/compat/os.h"
21 #include "../../src/engine/options.h"
22 #include "../../src/ui/color_manager.h"
23 #include "../../src/ui/column_view.h"
24 #include "../../src/ui/ui.h"
25 #include "../../src/utils/dynarray.h"
26 #include "../../src/utils/env.h"
27 #include "../../src/utils/fs.h"
28 #include "../../src/utils/macros.h"
29 #include "../../src/utils/matcher.h"
30 #include "../../src/utils/path.h"
31 #include "../../src/utils/str.h"
32 #include "../../src/utils/string_array.h"
33 #include "../../src/utils/utils.h"
34 #include "../../src/background.h"
35 #include "../../src/filelist.h"
36 #include "../../src/filtering.h"
37 #include "../../src/opt_handlers.h"
38 #include "../../src/status.h"
39 #include "../../src/undo.h"
40 
41 static int exec_func(OPS op, void *data, const char *src, const char *dst);
42 static int op_avail(OPS op);
43 static void format_none(int id, const void *data, size_t buf_len, char buf[]);
44 static void init_list(view_t *view);
45 static int init_pair_stub(short pair, short f, short b);
46 static int pair_content_stub(short pair, short *f, short *b);
47 static int pair_in_use_stub(short int pair);
48 static void move_pair_stub(short int from, short int to);
49 
50 void
fix_environ(void)51 fix_environ(void)
52 {
53 #ifdef _WIN32
54 	extern int _CRT_glob;
55 	extern void __wgetmainargs(int *, wchar_t ***, wchar_t ***, int, int *);
56 
57 	wchar_t **envp, **argv;
58 	int argc, si = 0;
59 	__wgetmainargs(&argc, &argv, &envp, _CRT_glob, &si);
60 #endif
61 }
62 
63 void
conf_setup(void)64 conf_setup(void)
65 {
66 	update_string(&cfg.slow_fs_list, "");
67 	update_string(&cfg.apropos_prg, "");
68 	update_string(&cfg.cd_path, "");
69 	update_string(&cfg.find_prg, "");
70 	update_string(&cfg.fuse_home, "");
71 	update_string(&cfg.time_format, "+");
72 	update_string(&cfg.vi_command, "");
73 	update_string(&cfg.vi_x_command, "");
74 	update_string(&cfg.ruler_format, "");
75 	update_string(&cfg.status_line, "");
76 	update_string(&cfg.grep_prg, "");
77 	update_string(&cfg.locate_prg, "");
78 	update_string(&cfg.media_prg, "");
79 	update_string(&cfg.border_filler, "");
80 	update_string(&cfg.tab_prefix, "");
81 	update_string(&cfg.tab_label, "");
82 	update_string(&cfg.tab_suffix, "");
83 
84 #ifndef _WIN32
85 	replace_string(&cfg.shell, "/bin/sh");
86 	update_string(&cfg.shell_cmd_flag, "-c");
87 #else
88 	replace_string(&cfg.shell, "cmd");
89 	update_string(&cfg.shell_cmd_flag, "/C");
90 #endif
91 	stats_update_shell_type(cfg.shell);
92 
93 	cfg.dot_dirs = DD_TREE_LEAFS_PARENT;
94 }
95 
96 void
conf_teardown(void)97 conf_teardown(void)
98 {
99 	update_string(&cfg.slow_fs_list, NULL);
100 	update_string(&cfg.apropos_prg, NULL);
101 	update_string(&cfg.cd_path, NULL);
102 	update_string(&cfg.find_prg, NULL);
103 	update_string(&cfg.fuse_home, NULL);
104 	update_string(&cfg.time_format, NULL);
105 	update_string(&cfg.vi_command, NULL);
106 	update_string(&cfg.vi_x_command, NULL);
107 	update_string(&cfg.ruler_format, NULL);
108 	update_string(&cfg.status_line, NULL);
109 	update_string(&cfg.grep_prg, NULL);
110 	update_string(&cfg.locate_prg, NULL);
111 	update_string(&cfg.media_prg, NULL);
112 	update_string(&cfg.border_filler, NULL);
113 	update_string(&cfg.tab_label, NULL);
114 	update_string(&cfg.shell, NULL);
115 	update_string(&cfg.shell_cmd_flag, NULL);
116 
117 	cfg.dot_dirs = 0;
118 }
119 
120 void
opt_handlers_setup(void)121 opt_handlers_setup(void)
122 {
123 	update_string(&lwin.view_columns, "");
124 	update_string(&lwin.view_columns_g, "");
125 	update_string(&lwin.sort_groups, "");
126 	update_string(&lwin.sort_groups_g, "");
127 	update_string(&lwin.preview_prg, "");
128 	update_string(&lwin.preview_prg_g, "");
129 	update_string(&rwin.view_columns, "");
130 	update_string(&rwin.view_columns_g, "");
131 	update_string(&rwin.sort_groups, "");
132 	update_string(&rwin.sort_groups_g, "");
133 	update_string(&rwin.preview_prg, "");
134 	update_string(&rwin.preview_prg_g, "");
135 
136 	conf_setup();
137 
138 	init_option_handlers();
139 }
140 
141 void
opt_handlers_teardown(void)142 opt_handlers_teardown(void)
143 {
144 	vle_opts_reset();
145 
146 	conf_teardown();
147 
148 	update_string(&lwin.view_columns, NULL);
149 	update_string(&lwin.view_columns_g, NULL);
150 	update_string(&lwin.sort_groups, NULL);
151 	update_string(&lwin.sort_groups_g, NULL);
152 	update_string(&lwin.preview_prg, NULL);
153 	update_string(&lwin.preview_prg_g, NULL);
154 	update_string(&rwin.view_columns, NULL);
155 	update_string(&rwin.view_columns_g, NULL);
156 	update_string(&rwin.sort_groups, NULL);
157 	update_string(&rwin.sort_groups_g, NULL);
158 	update_string(&rwin.preview_prg, NULL);
159 	update_string(&rwin.preview_prg_g, NULL);
160 }
161 
162 void
undo_setup(void)163 undo_setup(void)
164 {
165 	static int max_undo_levels = 0;
166 	un_init(&exec_func, &op_avail, NULL, &max_undo_levels);
167 }
168 
169 static int
exec_func(OPS op,void * data,const char * src,const char * dst)170 exec_func(OPS op, void *data, const char *src, const char *dst)
171 {
172 	return 0;
173 }
174 
175 static int
op_avail(OPS op)176 op_avail(OPS op)
177 {
178 	return 0;
179 }
180 
181 void
undo_teardown(void)182 undo_teardown(void)
183 {
184 	un_reset();
185 }
186 
187 void
view_setup(view_t * view)188 view_setup(view_t *view)
189 {
190 	char *error;
191 
192 	view->list_rows = 0;
193 	view->filtered = 0;
194 	view->list_pos = 0;
195 	view->dir_entry = NULL;
196 	view->hide_dot = 0;
197 	view->hide_dot_g = 0;
198 	view->invert = 1;
199 	view->selected_files = 0;
200 	view->ls_view = 0;
201 	view->ls_view_g = 0;
202 	view->miller_view = 0;
203 	view->miller_view_g = 0;
204 	view->window_rows = 0;
205 	view->run_size = 1;
206 
207 	assert_success(filter_init(&view->local_filter.filter, 1));
208 	assert_non_null(view->manual_filter = matcher_alloc("", 0, 0, "", &error));
209 	assert_success(filter_init(&view->auto_filter, 1));
210 
211 	strcpy(view->curr_dir, "/path");
212 	update_string(&view->custom.orig_dir, NULL);
213 
214 	view->sort[0] = SK_BY_NAME;
215 	memset(&view->sort[1], SK_NONE, sizeof(view->sort) - 1);
216 	memcpy(view->sort_g, view->sort, sizeof(view->sort_g));
217 
218 	view->custom.entry_count = 0;
219 	view->custom.entries = NULL;
220 
221 	view->local_filter.entry_count = 0;
222 	view->local_filter.entries = NULL;
223 }
224 
225 void
view_teardown(view_t * view)226 view_teardown(view_t *view)
227 {
228 	flist_free_view(view);
229 }
230 
231 void
columns_setup_column(int id)232 columns_setup_column(int id)
233 {
234 	columns_add_column_desc(id, &format_none);
235 }
236 
237 static void
format_none(int id,const void * data,size_t buf_len,char buf[])238 format_none(int id, const void *data, size_t buf_len, char buf[])
239 {
240 	buf[0] = '\0';
241 }
242 
243 void
columns_teardown(void)244 columns_teardown(void)
245 {
246 	columns_clear_column_descs();
247 	columns_set_line_print_func(NULL);
248 }
249 
250 void
histories_init(int size)251 histories_init(int size)
252 {
253 	cfg_resize_histories(0);
254 	cfg_resize_histories(size);
255 }
256 
257 void
create_dir(const char path[])258 create_dir(const char path[])
259 {
260 	assert_success(os_mkdir(path, 0700));
261 	assert_true(is_dir(path));
262 }
263 
264 void
create_file(const char path[])265 create_file(const char path[])
266 {
267 	FILE *const f = fopen(path, "w");
268 	assert_non_null(f);
269 	if(f != NULL)
270 	{
271 		fclose(f);
272 	}
273 }
274 
275 void
create_executable(const char path[])276 create_executable(const char path[])
277 {
278 	create_file(path);
279 	assert_success(access(path, F_OK));
280 	chmod(path, 0755);
281 	assert_success(access(path, X_OK));
282 }
283 
284 void
make_file(const char path[],const char contents[])285 make_file(const char path[], const char contents[])
286 {
287 	FILE *fp = fopen(path, "wb");
288 	assert_non_null(fp);
289 
290 	if(fp != NULL)
291 	{
292 		fputs(contents, fp);
293 		fclose(fp);
294 	}
295 }
296 
297 void
remove_dir(const char path[])298 remove_dir(const char path[])
299 {
300 	assert_success(rmdir(path));
301 }
302 
303 void
no_remove_dir(const char path[])304 no_remove_dir(const char path[])
305 {
306 	assert_failure(rmdir(path));
307 }
308 
309 void
remove_file(const char path[])310 remove_file(const char path[])
311 {
312 	assert_success(remove(path));
313 }
314 
315 void
no_remove_file(const char path[])316 no_remove_file(const char path[])
317 {
318 	assert_failure(remove(path));
319 }
320 
321 void
make_abs_path(char buf[],size_t buf_len,const char base[],const char sub[],const char cwd[])322 make_abs_path(char buf[], size_t buf_len, const char base[], const char sub[],
323 		const char cwd[])
324 {
325 	char local_buf[buf_len];
326 
327 	if(is_path_absolute(base))
328 	{
329 		snprintf(local_buf, buf_len, "%s%s%s", base, (sub[0] == '\0' ? "" : "/"),
330 				sub);
331 	}
332 	else
333 	{
334 		char cwd_buf[PATH_MAX + 1];
335 		if(cwd == NULL)
336 		{
337 			assert_non_null(get_cwd(cwd_buf, sizeof(cwd_buf)));
338 			cwd = cwd_buf;
339 		}
340 		snprintf(local_buf, buf_len, "%s/%s%s%s", cwd, base,
341 				(sub[0] == '\0' ? "" : "/"), sub);
342 	}
343 
344 	canonicalize_path(local_buf, buf, buf_len);
345 	if(!ends_with_slash(sub) && !is_root_dir(buf))
346 	{
347 		chosp(buf);
348 	}
349 }
350 
351 void
copy_file(const char src[],const char dst[])352 copy_file(const char src[], const char dst[])
353 {
354 	char buf[4*1024];
355 	size_t nread;
356 	FILE *const in = os_fopen(src, "rb");
357 	FILE *const out = os_fopen(dst, "wb");
358 
359 	assert_non_null(in);
360 	assert_non_null(out);
361 
362 	while((nread = fread(&buf, 1, sizeof(buf), in)) != 0U)
363 	{
364 		assert_int_equal(nread, fwrite(&buf, 1, nread, out));
365 	}
366 
367 	fclose(out);
368 	fclose(in);
369 }
370 
371 int
windows(void)372 windows(void)
373 {
374 #ifdef _WIN32
375 	return 1;
376 #else
377 	return 0;
378 #endif
379 }
380 
381 int
not_windows(void)382 not_windows(void)
383 {
384 #ifdef _WIN32
385 	return 0;
386 #else
387 	return 1;
388 #endif
389 }
390 
391 void
try_enable_utf8_locale(void)392 try_enable_utf8_locale(void)
393 {
394 	(void)setlocale(LC_ALL, "");
395 	if(!utf8_locale())
396 	{
397 		(void)setlocale(LC_ALL, "en_US.utf8");
398 	}
399 }
400 
401 int
utf8_locale(void)402 utf8_locale(void)
403 {
404 	return (vifm_wcwidth(L'丝') == 2);
405 }
406 
407 int
replace_matcher(matcher_t ** matcher,const char expr[])408 replace_matcher(matcher_t **matcher, const char expr[])
409 {
410 	char *error;
411 
412 	matcher_free(*matcher);
413 	*matcher = matcher_alloc(expr, FILTER_DEF_CASE_SENSITIVITY, 0, "", &error);
414 	free(error);
415 
416 	return (*matcher == NULL);
417 }
418 
419 void
setup_grid(view_t * view,int column_count,int list_rows,int init)420 setup_grid(view_t *view, int column_count, int list_rows, int init)
421 {
422 	view->window_cols = column_count;
423 	view->ls_view = 1;
424 	view->miller_view = 0;
425 	view->ls_transposed = 0;
426 	view->list_rows = list_rows;
427 	view->column_count = column_count;
428 	view->run_size = column_count;
429 	view->window_cells = column_count*view->window_rows;
430 
431 	if(init)
432 	{
433 		init_list(view);
434 	}
435 }
436 
437 void
setup_transposed_grid(view_t * view,int column_count,int list_rows,int init)438 setup_transposed_grid(view_t *view, int column_count, int list_rows, int init)
439 {
440 	view->window_cols = column_count;
441 	view->ls_view = 1;
442 	view->miller_view = 0;
443 	view->ls_transposed = 1;
444 	view->list_rows = list_rows;
445 	view->column_count = column_count;
446 	view->run_size = view->window_rows;
447 	view->window_cells = column_count*view->window_rows;
448 
449 	if(init)
450 	{
451 		init_list(view);
452 	}
453 }
454 
455 void
init_view_list(view_t * view)456 init_view_list(view_t *view)
457 {
458 	view->list_rows = 1;
459 	init_list(view);
460 }
461 
462 static void
init_list(view_t * view)463 init_list(view_t *view)
464 {
465 	int i;
466 
467 	view->dir_entry = dynarray_cextend(NULL,
468 			view->list_rows*sizeof(*view->dir_entry));
469 
470 	for(i = 0; i < view->list_rows; ++i)
471 	{
472 		view->dir_entry[i].name = strdup("");
473 		view->dir_entry[i].type = FT_REG;
474 		view->dir_entry[i].origin = view->curr_dir;
475 	}
476 }
477 
478 void
wait_for_bg(void)479 wait_for_bg(void)
480 {
481 	int counter = 0;
482 	while(bg_has_active_jobs(0))
483 	{
484 		usleep(5000);
485 		if(++counter > 100)
486 		{
487 			assert_fail("Waiting for too long.");
488 			break;
489 		}
490 	}
491 }
492 
493 void
file_is(const char path[],const char * lines[],int nlines)494 file_is(const char path[], const char *lines[], int nlines)
495 {
496 	FILE *fp = fopen(path, "r");
497 	if(fp == NULL)
498 	{
499 		assert_non_null(fp);
500 		return;
501 	}
502 
503 	int actual_nlines;
504 	char **actual_lines = read_file_lines(fp, &actual_nlines);
505 	fclose(fp);
506 
507 	assert_int_equal(nlines, actual_nlines);
508 
509 	int i;
510 	for(i = 0; i < MIN(nlines, actual_nlines); ++i)
511 	{
512 		assert_string_equal(lines[i], actual_lines[i]);
513 	}
514 
515 	free_string_array(actual_lines, actual_nlines);
516 }
517 
518 char *
mock_env(const char env[],const char with[])519 mock_env(const char env[], const char with[])
520 {
521 	char *value = NULL;
522 	update_string(&value, env_get("TMPDIR"));
523 	env_set("TMPDIR", with);
524 	return value;
525 }
526 
527 void
unmock_env(const char env[],char old_value[])528 unmock_env(const char env[], char old_value[])
529 {
530 	if(old_value != NULL)
531 	{
532 		env_set("TMPDIR", old_value);
533 	}
534 	else
535 	{
536 		env_remove("TMPDIR");
537 	}
538 	free(old_value);
539 }
540 
541 void
stub_colmgr(void)542 stub_colmgr(void)
543 {
544 	const colmgr_conf_t colmgr_conf = {
545 		.max_color_pairs = 256,
546 		.max_colors = 16,
547 		.init_pair = &init_pair_stub,
548 		.pair_content = &pair_content_stub,
549 		.pair_in_use = &pair_in_use_stub,
550 		.move_pair = &move_pair_stub,
551 	};
552 	colmgr_init(&colmgr_conf);
553 }
554 
555 static int
init_pair_stub(short pair,short f,short b)556 init_pair_stub(short pair, short f, short b)
557 {
558 	return 0;
559 }
560 
561 static int
pair_content_stub(short pair,short * f,short * b)562 pair_content_stub(short pair, short *f, short *b)
563 {
564 	*f = 0;
565 	*b = 0;
566 	return 0;
567 }
568 
569 static int
pair_in_use_stub(short int pair)570 pair_in_use_stub(short int pair)
571 {
572 	return 0;
573 }
574 
575 static void
move_pair_stub(short int from,short int to)576 move_pair_stub(short int from, short int to)
577 {
578 }
579 
580 void
reset_timestamp(const char path[])581 reset_timestamp(const char path[])
582 {
583 #ifndef _WIN32
584 	struct timeval tvs[2] = {};
585 	assert_success(utimes(path, tvs));
586 #else
587 	HANDLE file = CreateFileA(path, GENERIC_WRITE,
588 			FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
589 			FILE_ATTRIBUTE_NORMAL, NULL);
590 
591 	assert_true(file != INVALID_HANDLE_VALUE);
592 	if(file != INVALID_HANDLE_VALUE)
593 	{
594 		FILETIME time = { 1, 0 };
595 		assert_true(SetFileTime(file, &time, &time, &time));
596 		CloseHandle(file);
597 	}
598 #endif
599 }
600 
601 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
602 /* vim: set cinoptions+=t0 filetype=c : */
603