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