#include <stic.h> #include <unistd.h> /* rmdir() */ #include <stddef.h> /* NULL */ #include <stdlib.h> /* remove() */ #include <string.h> /* memset() */ #include <test-utils.h> #include "../../src/cfg/config.h" #include "../../src/compat/fs_limits.h" #include "../../src/compat/os.h" #include "../../src/ui/column_view.h" #include "../../src/ui/fileview.h" #include "../../src/ui/ui.h" #include "../../src/utils/fs.h" #include "../../src/utils/str.h" #include "../../src/utils/utils.h" #include "../../src/event_loop.h" #include "../../src/filelist.h" #include "../../src/filtering.h" #include "../../src/marks.h" #include "../../src/running.h" #include "../../src/sort.h" #include "../../src/status.h" #include "utils.h" static void verify_tree_node(column_data_t *cdt, int idx, const char expected[]); static void column_line_print(const char buf[], int offset, AlignType align, const char full_column[], const format_info_t *info); static int remove_selected(view_t *view, const dir_entry_t *entry, void *arg); static char cwd[PATH_MAX + 1], test_data[PATH_MAX + 1]; SETUP_ONCE() { assert_non_null(get_cwd(cwd, sizeof(cwd))); make_abs_path(test_data, sizeof(test_data), TEST_DATA_PATH, "", cwd); } SETUP() { conf_setup(); update_string(&cfg.fuse_home, "no"); view_setup(&lwin); curr_view = &lwin; other_view = &lwin; columns_set_line_print_func(&column_line_print); lwin.columns = columns_create(); } TEARDOWN() { conf_teardown(); view_teardown(&lwin); columns_set_line_print_func(NULL); } TEST(empty_directory_tree_is_created) { assert_success(os_mkdir(SANDBOX_PATH "/empty-dir", 0700)); assert_success(load_tree(&lwin, SANDBOX_PATH "/empty-dir", cwd)); assert_int_equal(1, lwin.list_rows); validate_tree(&lwin); assert_success(rmdir(SANDBOX_PATH "/empty-dir")); } TEST(empty_directory_tree_is_created_dotdirs_option) { cfg.dot_dirs |= DD_NONROOT_PARENT; assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(1, lwin.list_rows); validate_tree(&lwin); } TEST(complex_tree_is_built_correctly) { assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(12, lwin.list_rows); validate_tree(&lwin); } TEST(symlinks_are_loaded_as_files, IF(not_windows)) { assert_success(make_symlink(TEST_DATA_PATH, SANDBOX_PATH "/link")); assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(1, lwin.list_rows); assert_int_equal(0, lwin.filtered); validate_tree(&lwin); (void)filter_set(&lwin.local_filter.filter, "a"); assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(1, lwin.list_rows); assert_int_equal(1, lwin.filtered); validate_tree(&lwin); assert_success(remove(SANDBOX_PATH "/link")); } TEST(reloading_does_not_count_as_location_change) { cfg.cvoptions = CVO_LOCALFILTER; assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(12, lwin.list_rows); validate_tree(&lwin); (void)filter_set(&lwin.local_filter.filter, "dir"); load_view(&lwin); assert_int_equal(5, lwin.list_rows); validate_tree(&lwin); assert_false(filter_is_empty(&lwin.local_filter.filter)); cfg.cvoptions = 0; } TEST(tree_is_reloaded_manually_with_file_updates) { assert_success(os_mkdir(SANDBOX_PATH "/nested-dir", 0700)); create_file(SANDBOX_PATH "/a"); create_file(SANDBOX_PATH "/nested-dir/b"); assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(3, lwin.list_rows); /* On removal of single file in directory, it's replaced with ".." entry. */ assert_success(remove(SANDBOX_PATH "/nested-dir/b")); load_dir_list(&lwin, 1); assert_int_equal(3, lwin.list_rows); validate_tree(&lwin); assert_success(rmdir(SANDBOX_PATH "/nested-dir")); load_dir_list(&lwin, 1); assert_int_equal(1, lwin.list_rows); validate_tree(&lwin); assert_success(remove(SANDBOX_PATH "/a")); } TEST(tree_is_reloaded_automatically_with_file_updates) { struct stat st; create_file(SANDBOX_PATH "/a"); create_file(SANDBOX_PATH "/b"); /* Use presumably older timestamp for directory to be changed (we need one * second difference). */ assert_success(os_lstat(TEST_DATA_PATH, &st)); clone_attribs(SANDBOX_PATH, TEST_DATA_PATH, &st); assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(2, lwin.list_rows); check_if_filelist_has_changed(&lwin); ui_view_query_scheduled_event(&lwin); assert_success(remove(SANDBOX_PATH "/b")); check_if_filelist_has_changed(&lwin); curr_stats.load_stage = 2; assert_true(process_scheduled_updates_of_view(&lwin)); curr_stats.load_stage = 0; assert_int_equal(1, lwin.list_rows); validate_tree(&lwin); assert_success(remove(SANDBOX_PATH "/a")); } TEST(nested_directory_change_detection) { struct stat st1, st2; assert_success(os_mkdir(SANDBOX_PATH "/nested-dir", 0700)); create_file(SANDBOX_PATH "/nested-dir/a"); create_file(SANDBOX_PATH "/nested-dir/b"); /* Use presumably older timestamp for directory to be changed (we need one * second difference). */ assert_success(os_stat(TEST_DATA_PATH, &st1)); clone_attribs(SANDBOX_PATH "/nested-dir", TEST_DATA_PATH, &st1); assert_success(os_lstat(SANDBOX_PATH "/nested-dir", &st2)); /* On WINE time stamps aren't really cloned (even though success is * reported). */ if(not_wine()) { assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(3, lwin.list_rows); check_if_filelist_has_changed(&lwin); ui_view_query_scheduled_event(&lwin); assert_success(remove(SANDBOX_PATH "/nested-dir/b")); check_if_filelist_has_changed(&lwin); curr_stats.load_stage = 2; assert_true(process_scheduled_updates_of_view(&lwin)); curr_stats.load_stage = 0; assert_int_equal(2, lwin.list_rows); validate_tree(&lwin); } else { assert_success(remove(SANDBOX_PATH "/nested-dir/b")); } assert_success(remove(SANDBOX_PATH "/nested-dir/a")); assert_success(rmdir(SANDBOX_PATH "/nested-dir")); } TEST(excluding_dir_in_tree_excludes_its_children) { assert_success(os_mkdir(SANDBOX_PATH "/nested-dir", 0700)); create_file(SANDBOX_PATH "/nested-dir/a"); assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(2, lwin.list_rows); lwin.dir_entry[0].selected = 1; lwin.selected_files = 1; flist_custom_exclude(&lwin, 1); validate_tree(&lwin); assert_int_equal(0, lwin.selected_files); assert_int_equal(1, lwin.list_rows); assert_string_equal("..", lwin.dir_entry[0].name); assert_success(remove(SANDBOX_PATH "/nested-dir/a")); assert_success(rmdir(SANDBOX_PATH "/nested-dir")); } TEST(excluding_nested_dir_in_tree_adds_dummy) { assert_success(os_mkdir(SANDBOX_PATH "/nested-dir", 0700)); assert_success(os_mkdir(SANDBOX_PATH "/nested-dir/nested-dir2", 0700)); create_file(SANDBOX_PATH "/nested-dir/nested-dir2/a"); assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(3, lwin.list_rows); lwin.dir_entry[1].selected = 1; lwin.selected_files = 1; flist_custom_exclude(&lwin, 1); validate_tree(&lwin); assert_int_equal(0, lwin.selected_files); assert_int_equal(2, lwin.list_rows); assert_string_equal("..", lwin.dir_entry[1].name); assert_true(lwin.dir_entry[1].child_pos != 0); assert_success(remove(SANDBOX_PATH "/nested-dir/nested-dir2/a")); assert_success(rmdir(SANDBOX_PATH "/nested-dir/nested-dir2")); assert_success(rmdir(SANDBOX_PATH "/nested-dir")); } TEST(excluding_nested_dir_in_tree_can_skip_adding_dummy) { cfg.dot_dirs &= ~DD_TREE_LEAFS_PARENT; assert_success(os_mkdir(SANDBOX_PATH "/nested-dir", 0700)); assert_success(os_mkdir(SANDBOX_PATH "/nested-dir/nested-dir2", 0700)); create_file(SANDBOX_PATH "/nested-dir/nested-dir2/a"); assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(3, lwin.list_rows); lwin.dir_entry[1].selected = 1; lwin.selected_files = 1; flist_custom_exclude(&lwin, 1); validate_tree(&lwin); assert_int_equal(0, lwin.selected_files); assert_int_equal(1, lwin.list_rows); assert_success(remove(SANDBOX_PATH "/nested-dir/nested-dir2/a")); assert_success(rmdir(SANDBOX_PATH "/nested-dir/nested-dir2")); assert_success(rmdir(SANDBOX_PATH "/nested-dir")); } TEST(excluding_single_leaf_file_adds_dummy_correctly) { assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(12, lwin.list_rows); lwin.dir_entry[6].selected = 1; lwin.selected_files = 1; flist_custom_exclude(&lwin, 1); validate_tree(&lwin); assert_int_equal(0, lwin.selected_files); assert_int_equal(12, lwin.list_rows); } TEST(excluding_middle_directory_from_chain_adds_dummy_correctly) { assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(12, lwin.list_rows); /* First, hide one of directories to get dir1 -> dir2 -> dir4 -> file3. */ lwin.dir_entry[2].selected = 1; lwin.selected_files = 1; flist_custom_exclude(&lwin, 1); validate_tree(&lwin); assert_int_equal(0, lwin.selected_files); assert_int_equal(9, lwin.list_rows); /* Then exclude dir4. */ lwin.dir_entry[2].selected = 1; lwin.selected_files = 1; flist_custom_exclude(&lwin, 1); validate_tree(&lwin); assert_int_equal(0, lwin.selected_files); assert_int_equal(8, lwin.list_rows); } TEST(excluded_paths_do_not_appear_after_view_reload) { assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(12, lwin.list_rows); lwin.dir_entry[2].selected = 1; lwin.selected_files = 1; flist_custom_exclude(&lwin, 1); validate_tree(&lwin); assert_int_equal(0, lwin.selected_files); assert_int_equal(0, lwin.filtered); assert_int_equal(9, lwin.list_rows); load_dir_list(&lwin, 1); assert_int_equal(0, lwin.filtered); assert_int_equal(9, lwin.list_rows); validate_tree(&lwin); load_dir_list(&lwin, 1); assert_int_equal(0, lwin.filtered); assert_int_equal(9, lwin.list_rows); validate_tree(&lwin); } TEST(excluding_all_children_places_a_dummy) { assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(12, lwin.list_rows); lwin.dir_entry[3].selected = 1; lwin.dir_entry[4].selected = 1; lwin.selected_files = 2; lwin.list_pos = 4; flist_custom_exclude(&lwin, 1); validate_tree(&lwin); assert_int_equal(0, lwin.selected_files); assert_int_equal(0, lwin.filtered); assert_int_equal(3, lwin.list_pos); assert_int_equal(11, lwin.list_rows); } TEST(zapping_a_tree_reassigns_children) { assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(12, lwin.list_rows); validate_tree(&lwin); lwin.dir_entry[0].selected = 1; lwin.selected_files = 1; assert_int_equal(1, zap_entries(&lwin, lwin.dir_entry, &lwin.list_rows, &remove_selected, NULL, 0, 0)); assert_int_equal(11, lwin.list_rows); validate_tree(&lwin); } TEST(tree_sorting_considers_structure) { lwin.hide_dot = 1; view_set_sort(lwin.sort, SK_BY_NAME, SK_NONE); assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(10, lwin.list_rows); validate_tree(&lwin); assert_string_equal("dir1", lwin.dir_entry[0].name); assert_string_equal("dir2", lwin.dir_entry[1].name); assert_string_equal("dir3", lwin.dir_entry[2].name); assert_string_equal("file1", lwin.dir_entry[3].name); assert_string_equal("file2", lwin.dir_entry[4].name); assert_string_equal("dir4", lwin.dir_entry[5].name); assert_string_equal("file3", lwin.dir_entry[6].name); assert_string_equal("file4", lwin.dir_entry[7].name); assert_string_equal("dir5", lwin.dir_entry[8].name); assert_string_equal("file5", lwin.dir_entry[9].name); stats_init(&cfg); view_set_sort(lwin.sort, SK_BY_NITEMS, SK_NONE); sort_view(&lwin); assert_string_equal("dir1", lwin.dir_entry[0].name); assert_string_equal("dir2", lwin.dir_entry[1].name); assert_string_equal("dir4", lwin.dir_entry[2].name); assert_string_equal("file3", lwin.dir_entry[3].name); assert_string_equal("dir3", lwin.dir_entry[4].name); assert_string_equal("file1", lwin.dir_entry[5].name); assert_string_equal("file2", lwin.dir_entry[6].name); assert_string_equal("file4", lwin.dir_entry[7].name); assert_string_equal("dir5", lwin.dir_entry[8].name); assert_string_equal("file5", lwin.dir_entry[9].name); stats_reset(&cfg); } TEST(short_paths_consider_tree_structure) { char name[NAME_MAX + 1]; memset(&cfg.type_decs, '\0', sizeof(cfg.type_decs)); (void)filter_set(&lwin.local_filter.filter, "2"); assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(2, lwin.list_rows); validate_tree(&lwin); get_short_path_of(&lwin, &lwin.dir_entry[0], 1, 1, sizeof(name), name); assert_string_equal("dir1/dir2", name); get_short_path_of(&lwin, &lwin.dir_entry[1], 1, 1, sizeof(name), name); assert_string_equal("dir3/file2", name); } TEST(tree_prefixes_are_correct) { size_t prefix_len = 0U; column_data_t cdt = { .view = &lwin, .prefix_len = &prefix_len }; memset(&cfg.type_decs, '\0', sizeof(cfg.type_decs)); lwin.hide_dot = 1; assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(10, lwin.list_rows); validate_tree(&lwin); verify_tree_node(&cdt, 0, "dir1"); verify_tree_node(&cdt, 1, "|-- dir2"); verify_tree_node(&cdt, 2, "| |-- dir3"); verify_tree_node(&cdt, 3, "| | |-- file1"); verify_tree_node(&cdt, 4, "| | `-- file2"); verify_tree_node(&cdt, 5, "| `-- dir4"); verify_tree_node(&cdt, 6, "| `-- file3"); verify_tree_node(&cdt, 7, "`-- file4"); verify_tree_node(&cdt, 8, "dir5"); verify_tree_node(&cdt, 9, "`-- file5"); } TEST(dotdirs_do_not_mess_up_change_detection) { cfg.dot_dirs |= DD_NONROOT_PARENT; assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); /* Discard results of the first check. */ check_if_filelist_has_changed(&lwin); (void)ui_view_query_scheduled_event(&lwin); check_if_filelist_has_changed(&lwin); assert_int_equal(UUE_NONE, ui_view_query_scheduled_event(&lwin)); check_if_filelist_has_changed(&lwin); assert_int_equal(UUE_NONE, ui_view_query_scheduled_event(&lwin)); check_if_filelist_has_changed(&lwin); assert_int_equal(UUE_NONE, ui_view_query_scheduled_event(&lwin)); } TEST(tree_reload_preserves_selection) { assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); lwin.dir_entry[0].selected = 1; lwin.dir_entry[1].selected = 1; lwin.dir_entry[2].selected = 1; lwin.selected_files = 3; load_dir_list(&lwin, 1); assert_true(lwin.dir_entry[0].selected); assert_true(lwin.dir_entry[1].selected); assert_true(lwin.dir_entry[2].selected); assert_int_equal(3, lwin.selected_files); } TEST(marks_unit_is_able_to_find_leafs) { assert_success(os_mkdir(SANDBOX_PATH "/empty-dir", 0700)); assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); marks_set_special(&lwin, '<', lwin.dir_entry[1].origin, lwin.dir_entry[1].name); assert_int_equal(1, marks_find_in_view(&lwin, '<')); assert_success(rmdir(SANDBOX_PATH "/empty-dir")); } TEST(leafs_are_treated_correctly_on_reloading_saving_pos) { assert_success(os_mkdir(SANDBOX_PATH "/dir", 0700)); assert_success(os_mkdir(SANDBOX_PATH "/dir/subdir", 0700)); assert_success(os_mkdir(SANDBOX_PATH "/dir/subdir/subsubdir", 0700)); create_file(SANDBOX_PATH "/dir/file"); assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); lwin.list_pos = 3; create_file(SANDBOX_PATH "/dir/subdir/subsubdir/file"); load_view(&lwin); assert_int_equal(4, lwin.list_pos); assert_success(remove(SANDBOX_PATH "/dir/file")); assert_success(remove(SANDBOX_PATH "/dir/subdir/subsubdir/file")); assert_success(rmdir(SANDBOX_PATH "/dir/subdir/subsubdir")); assert_success(rmdir(SANDBOX_PATH "/dir/subdir")); assert_success(rmdir(SANDBOX_PATH "/dir")); } TEST(cursor_is_set_on_previous_file) { make_abs_path(lwin.curr_dir, sizeof(lwin.curr_dir), TEST_DATA_PATH, "tree", cwd); load_dir_list(&lwin, 1); assert_int_equal(3, lwin.list_rows); lwin.list_pos = 1; assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(8, lwin.list_pos); } TEST(tree_out_of_cv_with_single_element) { char path[PATH_MAX + 1]; snprintf(path, sizeof(path), "%s/%s", test_data, "existing-files/a"); flist_custom_start(&lwin, "test"); flist_custom_add(&lwin, path); assert_true(flist_custom_finish(&lwin, CV_REGULAR, 0) == 0); assert_success(load_tree(&lwin, TEST_DATA_PATH, cwd)); assert_int_equal(1, lwin.list_rows); } TEST(tree_out_of_cv_with_two_elements) { char path[PATH_MAX + 1]; flist_custom_start(&lwin, "test"); snprintf(path, sizeof(path), "%s/%s", test_data, "existing-files/a"); flist_custom_add(&lwin, path); snprintf(path, sizeof(path), "%s/%s", test_data, "read/dos-eof"); flist_custom_add(&lwin, path); assert_true(flist_custom_finish(&lwin, CV_REGULAR, 0) == 0); assert_success(load_tree(&lwin, TEST_DATA_PATH, cwd)); assert_int_equal(5, lwin.list_rows); } TEST(opening_non_toplevel_dummy_is_not_the_same_as_leaving_tree) { create_dir(SANDBOX_PATH "/a"); create_dir(SANDBOX_PATH "/a/b"); assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(3, lwin.list_rows); assert_string_equal("..", lwin.dir_entry[2].name); char *saved_cwd = save_cwd(); lwin.list_pos = 2; rn_open(&lwin, FHE_NO_RUN); restore_cwd(saved_cwd); char expected_path[PATH_MAX + 1]; make_abs_path(expected_path, sizeof(expected_path), SANDBOX_PATH, "a", cwd); assert_true(paths_are_same(expected_path, flist_get_dir(&lwin))); remove_dir(SANDBOX_PATH "/a/b"); remove_dir(SANDBOX_PATH "/a"); } TEST(dummies_of_leaf_directories_can_be_disabled) { create_dir(SANDBOX_PATH "/a"); create_dir(SANDBOX_PATH "/a/b"); cfg.dot_dirs &= ~DD_TREE_LEAFS_PARENT; assert_success(load_tree(&lwin, SANDBOX_PATH, cwd)); assert_int_equal(2, lwin.list_rows); assert_string_equal("a", lwin.dir_entry[0].name); assert_string_equal("b", lwin.dir_entry[1].name); remove_dir(SANDBOX_PATH "/a/b"); remove_dir(SANDBOX_PATH "/a"); } TEST(full_path_matchers_work_in_trees) { assert_success(replace_matcher(&lwin.manual_filter, "{{*/dir[135]/file[145]}}")); assert_success(load_tree(&lwin, TEST_DATA_PATH "/tree", cwd)); assert_int_equal(9, lwin.list_rows); validate_tree(&lwin); } TEST(nesting_limit) { assert_success(load_limited_tree(&lwin, TEST_DATA_PATH "/tree", cwd, 0)); assert_int_equal(3, lwin.list_rows); assert_success(load_limited_tree(&lwin, TEST_DATA_PATH "/tree", cwd, 1)); assert_int_equal(7, lwin.list_rows); assert_success(load_limited_tree(&lwin, TEST_DATA_PATH "/tree", cwd, 2)); assert_int_equal(9, lwin.list_rows); assert_success(load_limited_tree(&lwin, TEST_DATA_PATH "/tree", cwd, 3)); assert_int_equal(12, lwin.list_rows); assert_success(load_limited_tree(&lwin, TEST_DATA_PATH "/tree", cwd, 4)); assert_int_equal(12, lwin.list_rows); } static void verify_tree_node(column_data_t *cdt, int idx, const char expected[]) { char name[NAME_MAX + 1]; cdt->entry = &cdt->view->dir_entry[idx]; cdt->line_pos = idx; const format_info_t info = { .data = cdt, .id = -1 }; format_name(NULL, sizeof(name), name, &info); assert_string_equal(expected, name); } static void column_line_print(const char buf[], int offset, AlignType align, const char full_column[], const format_info_t *info) { /* Do nothing. */ } static int remove_selected(view_t *view, const dir_entry_t *entry, void *arg) { return !entry->selected; } /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ /* vim: set cinoptions+=t0 filetype=c : */