#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "util.h" #include "client.h" #include "wm.h" typedef struct { char logfilepath[PATH_MAX]; char *jsonstr; char *logjsonstr; } TestGroup1State; // store a copy of the nodes created in test2_setup, to check if any // of the tests modified them static NodeArray *test_group2_nodes_copy = NULL; static void test_wm_nodearray_push(void **state) { TreeNode *node = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *node1 = wm_treenode_new(NODE_VERTICAL, node); assert_non_null(node); assert_non_null(node1); node1->id = 123; assert_null(node->parent); assert_ptr_equal(node1->parent, node); wm_nodearray_push(node->children, node1); assert_int_equal(node->children->size, 1); assert_ptr_equal(node->children->nodes[0], node1); assert_int_equal(node1->id, 123); assert_int_equal(node->children->nodes[0]->id, 123); wm_treenode_free(node); wm_treenode_free(node1); } static void test_wm_treenode_new(void **state) { TreeNode *node = wm_treenode_new(NODE_VERTICAL, NULL); assert_non_null(node); assert_null(node->client); assert_non_null(node->children->nodes); assert_int_equal(node->children->size, 0); assert_int_equal(node->type, NODE_VERTICAL); wm_treenode_free(node); } static void test_wm_treenode_split_space(void **state) { /* vertical */ TreeNode *parent = wm_treenode_new(NODE_VERTICAL, NULL); assert_non_null(parent); parent->pos.x = 0; parent->pos.y = 0; parent->pos.w = 200; parent->pos.h = 200; TreeNode *child1 = wm_treenode_new(NODE_CLIENT, parent); TreeNode *child2 = wm_treenode_new(NODE_CLIENT, parent); assert_non_null(child1); assert_non_null(child2); wm_treenode_split_space(parent, &child1->pos, &child2->pos); assert_int_equal(child1->pos.x, 0); assert_int_equal(child1->pos.y, 0); assert_int_equal(child1->pos.w, 100); assert_int_equal(child1->pos.h, 200); assert_int_equal(child2->pos.x, 100); assert_int_equal(child2->pos.y, 0); assert_int_equal(child2->pos.w, 100); assert_int_equal(child2->pos.h, 200); wm_treenode_free(parent); wm_treenode_free(child1); wm_treenode_free(child2); /* horizontal */ parent = wm_treenode_new(NODE_HORIZONTAL, NULL); assert_non_null(parent); parent->pos.x = 0; parent->pos.y = 0; parent->pos.w = 200; parent->pos.h = 200; child1 = wm_treenode_new(NODE_CLIENT, parent); child2 = wm_treenode_new(NODE_CLIENT, parent); assert_non_null(child1); assert_non_null(child2); wm_treenode_split_space(parent, &child1->pos, &child2->pos); assert_int_equal(child1->pos.x, 0); assert_int_equal(child1->pos.y, 0); assert_int_equal(child1->pos.w, 200); assert_int_equal(child1->pos.h, 100); assert_int_equal(child2->pos.x, 0); assert_int_equal(child2->pos.y, 100); assert_int_equal(child2->pos.w, 200); assert_int_equal(child2->pos.h, 100); wm_treenode_free(parent); wm_treenode_free(child1); wm_treenode_free(child2); } static void test_wm_all_nodes_to_array(void **state) { TreeNode *root = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *node1 = wm_treenode_new(NODE_CLIENT, NULL); TreeNode *node2 = wm_treenode_new(NODE_CLIENT, NULL); TreeNode *node3 = wm_treenode_new(NODE_CLIENT, NULL); assert_non_null(root); assert_non_null(node1); assert_non_null(node2); assert_non_null(node3); const unsigned long ids[] = {1, 2, 3, 4}; root->id = ids[0]; node1->id = ids[1]; node2->id = ids[2]; node3->id = ids[3]; wm_nodearray_push(root->children, node1); wm_nodearray_push(root->children, node2); wm_nodearray_push(root->children, node3); assert_int_equal(root->children->size, 3); assert_ptr_equal(root->children->nodes[0], node1); assert_ptr_equal(root->children->nodes[1], node2); assert_ptr_equal(root->children->nodes[2], node3); NodeArray *all_nodes = wm_all_nodes_to_array(root); assert_non_null(all_nodes); assert_int_equal(all_nodes->size, 4); assert_in_set(((TreeNode*)all_nodes->nodes[0])->id, ids, 4); assert_in_set(((TreeNode*)all_nodes->nodes[1])->id, ids, 4); assert_in_set(((TreeNode*)all_nodes->nodes[2])->id, ids, 4); assert_in_set(((TreeNode*)all_nodes->nodes[3])->id, ids, 4); wm_treenode_free(root); wm_treenode_free(node1); wm_treenode_free(node2); wm_treenode_free(node3); wm_nodearray_free(all_nodes); } static void test_wm_find_client_nodes(void **state) { TreeNode *root = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *node1 = wm_treenode_new(NODE_CLIENT, NULL); TreeNode *node2 = wm_treenode_new(NODE_CLIENT, NULL); assert_non_null(root); assert_non_null(node1); assert_non_null(node2); node1->client = (Client*)0x123; node2->client = (Client*)0x456; const unsigned long ids[] = {123, 456}; node1->id = ids[0]; node2->id = ids[1]; wm_nodearray_push(root->children, node1); wm_nodearray_push(root->children, node2); assert_int_equal(root->children->size, 2); assert_ptr_equal(root->children->nodes[0], node1); assert_ptr_equal(root->children->nodes[1], node2); NodeArray *client_nodes = wm_treenode_find_client_nodes(root); assert_non_null(client_nodes); assert_int_equal(client_nodes->size, 2); assert_in_set((client_nodes->nodes[0])->id, ids, 2); assert_in_set((client_nodes->nodes[1])->id, ids, 2); wm_treenode_free(root); wm_treenode_free(node1); wm_treenode_free(node2); wm_nodearray_free(client_nodes); } static void test_wm_treenode_remove_client1(void **state) { TreeNode *root = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *parent_node1 = wm_treenode_new(NODE_VERTICAL, root); TreeNode *parent_node2 = wm_treenode_new(NODE_HORIZONTAL, root); TreeNode *client_node1 = wm_treenode_new(NODE_CLIENT, parent_node1); TreeNode *client_node2 = wm_treenode_new(NODE_CLIENT, parent_node1); TreeNode *client_node3 = wm_treenode_new(NODE_CLIENT, parent_node2); TreeNode *client_node4 = wm_treenode_new(NODE_CLIENT, parent_node2); assert_non_null(root); assert_non_null(parent_node1); assert_non_null(parent_node2); assert_non_null(client_node1); assert_non_null(client_node2); assert_non_null(client_node3); assert_non_null(client_node4); wm_nodearray_push(root->children, parent_node1); wm_nodearray_push(root->children, parent_node2); wm_nodearray_push(parent_node1->children, client_node1); wm_nodearray_push(parent_node1->children, client_node2); wm_nodearray_push(parent_node2->children, client_node3); wm_nodearray_push(parent_node2->children, client_node4); Workspace ws = (Workspace) { .tree = root, .monitor = &(Monitor) {0}, }; Client client1 = (Client) {.ws = &ws, .name = ""}; Client client2 = (Client) {.ws = &ws, .name = ""}; Client client3 = (Client) {.ws = &ws, .name = ""}; Client client4 = (Client) {.ws = &ws, .name = ""}; client_node1->client = &client1; client_node2->client = &client2; client_node3->client = &client3; client_node4->client = &client4; root->pos.x = 0; root->pos.y = 0; root->pos.w = 1000; root->pos.w = 1000; wm_treenode_split_space(root, &parent_node1->pos, &parent_node2->pos); wm_treenode_split_space(parent_node1, &client_node1->pos, &client_node2->pos); wm_treenode_split_space(parent_node2, &client_node3->pos, &client_node4->pos); TreeNode *new_client_node = wm_treenode_remove_client(&(Wm) {0}, root, &client4); assert_non_null(new_client_node); assert_ptr_equal(new_client_node, parent_node2); assert_int_equal(parent_node2->type, NODE_CLIENT); assert_ptr_equal(parent_node2->client, &client3); assert_int_equal(parent_node2->children->size, 0); wm_treenode_free(root); wm_treenode_free(parent_node1); wm_treenode_free(parent_node2); wm_treenode_free(client_node1); wm_treenode_free(client_node2); } static void test_wm_treenode_remove_client2(void **state) { TreeNode *root = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *parent_node1 = wm_treenode_new(NODE_VERTICAL, root); TreeNode *client_node1 = wm_treenode_new(NODE_CLIENT, root); TreeNode *client_node2 = wm_treenode_new(NODE_CLIENT, parent_node1); TreeNode *client_node3 = wm_treenode_new(NODE_CLIENT, parent_node1); assert_non_null(root); assert_non_null(parent_node1); assert_non_null(client_node1); assert_non_null(client_node2); assert_non_null(client_node3); TreeNode parent_node1_val = *parent_node1; wm_nodearray_push(root->children, parent_node1); wm_nodearray_push(root->children, client_node1); wm_nodearray_push(parent_node1->children, client_node2); wm_nodearray_push(parent_node1->children, client_node3); Workspace ws = (Workspace) { .tree = root, .monitor = &(Monitor) {0}, }; Client client1 = (Client) {.ws = &ws, .name = ""}; Client client2 = (Client) {.ws = &ws, .name = ""}; Client client3 = (Client) {.ws = &ws, .name = ""}; client_node1->client = &client1; client_node2->client = &client2; client_node3->client = &client3; root->pos.x = 0; root->pos.y = 0; root->pos.w = 1000; root->pos.w = 1000; wm_treenode_split_space(root, &parent_node1->pos, &client_node1->pos); wm_treenode_split_space(parent_node1, &client_node2->pos, &client_node3->pos); TreeNode *new_client_node = wm_treenode_remove_client(&(Wm) {0}, root, &client1); assert_non_null(new_client_node); assert_ptr_equal(new_client_node, client_node2); assert_int_equal(root->id, parent_node1_val.id); assert_ptr_equal(root->children, parent_node1_val.children); assert_int_equal(root->children->size, 2); assert_ptr_equal(root->children->nodes[0], client_node2); assert_ptr_equal(root->children->nodes[1], client_node3); assert_ptr_equal(client_node2->parent, root); assert_ptr_equal(client_node3->parent, root); wm_treenode_free(root); wm_treenode_free(client_node2); wm_treenode_free(client_node3); } static void test_wm_ptrarray_2d_index(void **state) { size_t x = 5; size_t y = 10; UIntArray *uintarr = wm_uintarray_new(); _Static_assert(sizeof(uint64_t) == sizeof(uint64_t*), "static assert failed"); for (size_t i = 0; i < x; i++) { wm_uintarray_push(uintarr, (uint64_t)calloc(y, sizeof(uintptr_t))); } for (size_t i = 0; i < uintarr->size; i++) { for (size_t j = 0; j < y; j++) { ((uint64_t**)uintarr->elements)[i][j] = i * j; } } for (size_t i = 0; i < uintarr->size; i++) { for (size_t j = 0; j < y; j++) { assert_int_equal(wm_uintarray_2d_index(uintarr, i, j), i * j); } } for (size_t i = 0; i < uintarr->size; i++) { free((void*)uintarr->elements[i]); } wm_uintarray_free(uintarr); } static void test_wm_treenode_to_str(void **state) { TreeNode *node = wm_treenode_new(NODE_CLIENT, (void*)54321); node->pos.x = 1; node->pos.y = 2; node->pos.w = 3; node->pos.h = 4; node->id = 5; node->client = &(Client) {.name = "client_name", .is_pid_set = true, .pid = 12341234}; char *str = wm_treenode_to_str(node); assert_non_null(strstr(str, "\"type\":\"NODE_CLIENT\",")); assert_non_null(strstr(str, "\"parent\":54321,")); assert_non_null(strstr(str, "\"children\":[],")); assert_non_null(strstr(str, "\"pos\":{")); assert_non_null(strstr(str, "\"x\":1,")); assert_non_null(strstr(str, "\"y\":2,")); assert_non_null(strstr(str, "\"w\":3,")); assert_non_null(strstr(str, "\"h\":4")); assert_non_null(strstr(str, "\"client\":{")); assert_non_null(strstr(str, "\"name\":\"client_name\"")); assert_non_null(strstr(str, "\"is_pid_set\":true")); assert_non_null(strstr(str, "\"pid\":12341234")); assert_non_null(strstr(str, "\"id\":5")); wm_treenode_free(node); free(str); } static void test_wm_json_obj_to_treenode(void **state) { TestGroup1State *_state = (TestGroup1State*)(*state); struct json_object *parsed_json = json_tokener_parse(_state->jsonstr); assert_non_null(parsed_json); TreeNode *node = wm_json_obj_to_treenode(parsed_json); assert_int_equal(node->type, NODE_VERTICAL); assert_int_equal(node->parent, 0); assert_int_equal(node->children->size, 2); assert_int_equal(node->pos.x, 1); assert_int_equal(node->pos.y, 2); assert_int_equal(node->pos.w, 3); assert_int_equal(node->pos.h, 4); assert_null(node->client); TreeNode *child1 = node->children->nodes[0]; assert_int_equal(child1->type, NODE_CLIENT); // assert_int_equal(child1->parent, 0); assert_int_equal(child1->children->size, 0); assert_int_equal(child1->pos.x, 2); assert_int_equal(child1->pos.y, 2); assert_int_equal(child1->pos.w, 798); assert_int_equal(child1->pos.h, 896); assert_non_null(child1->client); assert_string_equal(child1->client->name, "child1_client_name"); assert_true(child1->client->is_pid_set); assert_int_equal(child1->client->pid, 19058); assert_int_equal(child1->id, 10); TreeNode *child2 = node->children->nodes[1]; assert_int_equal(child2->type, NODE_CLIENT); // assert_int_equal(child2->parent, 0); assert_int_equal(child2->children->size, 0); assert_int_equal(child2->pos.x, 800); assert_int_equal(child2->pos.y, 2); assert_int_equal(child2->pos.w, 798); assert_int_equal(child2->pos.h, 896); assert_non_null(child2->client); assert_string_equal(child2->client->name, "child2_client_name"); assert_true(child2->client->is_pid_set); assert_int_equal(child2->client->pid, 19063); assert_int_equal(child2->id, 11); json_object_put(parsed_json); free(node->children->nodes[0]->client->name); free(node->children->nodes[0]->client); wm_treenode_free(node->children->nodes[0]); free(node->children->nodes[1]->client->name); free(node->children->nodes[1]->client); wm_treenode_free(node->children->nodes[1]); wm_treenode_free(node); } static void test_wm_read_log(void **state) { TestGroup1State *_state = (TestGroup1State*)(*state); UIntArray *entries = wm_read_log(_state->logfilepath); assert_int_equal(entries->size, 1); LogEntry *entry = (void*)wm_uintarray_at(entries, 0); assert_int_equal(entry->timestamp, 1705601049); assert_string_equal(entry->function_name, "wm_kb_spawn"); assert_true(entry->after); // TODO check nodes free(entry->workspaces->nodes[2]->children->nodes[0]->client->name); free(entry->workspaces->nodes[2]->children->nodes[0]->client); wm_treenode_free(entry->workspaces->nodes[2]->children->nodes[0]); free(entry->workspaces->nodes[2]->children->nodes[1]->client->name); free(entry->workspaces->nodes[2]->children->nodes[1]->client); wm_treenode_free(entry->workspaces->nodes[2]->children->nodes[1]); wm_treenode_free(entry->workspaces->nodes[2]); wm_nodearray_free(entry->workspaces); free(entry); wm_uintarray_free(entries); } uint64_t simple_update_cost_function(TreeNode* node1, TreeNode* node2) { return 10; } static void test_wm_logentries_calculate_distances(void **state) { TestGroup1State *_state = (TestGroup1State*)(*state); UIntArray *entries = wm_read_log(_state->logfilepath); TreeNode *node = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *child = wm_treenode_new(NODE_CLIENT, NULL); wm_treenode_add_child(node, child); wm_logentries_calculate_distances(entries, node, &simple_update_cost_function); LogEntry *entry = (void*)wm_uintarray_at(entries, 0); // TODO check node distances free(entry->workspaces->nodes[2]->children->nodes[0]->client->name); free(entry->workspaces->nodes[2]->children->nodes[0]->client); free(entry->workspaces->nodes[2]->children->nodes[1]->client->name); free(entry->workspaces->nodes[2]->children->nodes[1]->client); wm_treenode_free(entry->workspaces->nodes[2]->children->nodes[0]); wm_treenode_free(entry->workspaces->nodes[2]->children->nodes[1]); wm_logentries_free(entries); wm_treenode_free(node); wm_treenode_free(child); } static void test_wm_keybind_str_to_mask_keysym(void **state) { char *keybind1 = "Windows+Shift+h"; char *keybind2 = "Alt+1"; char *keybind3 = "Windows+Alt+Shift+j"; char *keybind4 = "CapsLock+k"; KeySym *ret; ret = wm_keybind_string_to_mask_keysym(keybind1); assert_int_equal(ret[0], Mod4Mask | ShiftMask); assert_int_equal(ret[1], XK_h); free(ret); ret = wm_keybind_string_to_mask_keysym(keybind2); assert_int_equal(ret[0], Mod1Mask); assert_int_equal(ret[1], XK_1); free(ret); ret = wm_keybind_string_to_mask_keysym(keybind3); assert_int_equal(ret[0], Mod4Mask | Mod1Mask | ShiftMask); assert_int_equal(ret[1], XK_j); free(ret); ret = wm_keybind_string_to_mask_keysym(keybind4); assert_int_equal(ret[0], LockMask); assert_int_equal(ret[1], XK_k); free(ret); } static void test_wm_config_parse_bind_command(void **state) { char line1[] = "keybind Windows+h focus left"; ConfigFile file; Config config; ConfigCommand command; char tmp[] = "/tmp/XXXXXX"; mkstemp(tmp); wm_configfile_init(&file, tmp); wm_configcommand_init(&command); ParserResult res = wm_configfile_parse_line(&file, &config, line1, &command); assert_true(res.success); Keybind keybind = wm_config_parse_bind_command(&command); assert_ptr_equal(keybind.function, &wm_kb_focus_dir); assert_ptr_equal(keybind.args.i, LEFT); wm_configfile_free(&file); wm_configcommand_free(&command); char line2[] = "keybind Alt+j move down"; file = (ConfigFile) {0}; config = (Config) {0}; command = (ConfigCommand) {0}; wm_configfile_init(&file, tmp); wm_configcommand_init(&command); res = wm_configfile_parse_line(&file, &config, line2, &command); assert_true(res.success); keybind = wm_config_parse_bind_command(&command); assert_ptr_equal(keybind.function, &wm_kb_move_dir); assert_ptr_equal(keybind.args.i, DOWN); wm_configfile_free(&file); wm_configcommand_free(&command); char line3[] = "keybind Alt+1 switch_ws 1"; file = (ConfigFile) {0}; config = (Config) {0}; command = (ConfigCommand) {0}; wm_configfile_init(&file, tmp); wm_configcommand_init(&command); res = wm_configfile_parse_line(&file, &config, line3, &command); assert_true(res.success); keybind = wm_config_parse_bind_command(&command); assert_ptr_equal(keybind.function, &wm_kb_switch_ws); assert_ptr_equal(keybind.args.i, 1); wm_configfile_free(&file); wm_configcommand_free(&command); unlink(tmp); } static void test_wm_config(void **state) { char configstr[] = "border_color #112233\n" "focused_border_color #445566\n" "border_width 1\n" "keybind Windows+Alt+Shift+h focus left\n" "focus_on_motion true\n"; char tmp[] = "/tmp/XXXXXX"; mkstemp(tmp); int fd = open(tmp, O_CREAT | O_TRUNC | O_RDWR, 0664); if (fd < 0) { perror("open"); fail(); } int ret = write(fd, configstr, sizeof(configstr)); assert_int_equal(ret, sizeof(configstr)); ret = close(fd); if (fd < 0) { perror("close"); fail(); } ConfigFile file = (ConfigFile) {0}; Config config = (Config) {0}; wm_cfg_init_def(&config); wm_configfile_init(&file, tmp); wm_configfile_read(&file, &config); assert_string_equal(config.border_col, "#112233"); assert_string_equal(config.focused_border_col, "#445566"); assert_int_equal(config.border_width, 1); bool found_keybind = false; for (size_t i = 0; i < config.kb_count; i++) { if (config.keybinds[i].mask == (Mod4Mask | Mod1Mask | ShiftMask) && config.keybinds[i].keysym == XK_h && config.keybinds[i].function == &wm_kb_focus_dir && config.keybinds[i].args.i == LEFT) found_keybind = true; } assert_true(found_keybind); assert_true(config.focus_on_motion); wm_configfile_free(&file); wm_keybinds_free(&config); free(config.keybinds); unlink(tmp); } static void test_wm_postorder_traversal(void **state) { TreeNode *node1 = (TreeNode*)*state; NodeArray *postorder = wm_postorder_traversal(node1); assert_non_null(postorder); assert_int_equal(postorder->size, 8); assert_int_equal(postorder->nodes[0]->id, 4); assert_int_equal(postorder->nodes[1]->id, 5); assert_int_equal(postorder->nodes[2]->id, 6); assert_int_equal(postorder->nodes[3]->id, 2); assert_int_equal(postorder->nodes[4]->id, 7); assert_int_equal(postorder->nodes[5]->id, 8); assert_int_equal(postorder->nodes[6]->id, 3); assert_int_equal(postorder->nodes[7]->id, 1); wm_nodearray_free(postorder); } static void test_wm_treenode_lmd(void **state) { TreeNode *node1 = (TreeNode*)*state; TreeNode *node2 = node1->children->nodes[0]; TreeNode *node3 = node1->children->nodes[1]; TreeNode *node4 = node2->children->nodes[0]; TreeNode *node5 = node2->children->nodes[1]; TreeNode *node6 = node2->children->nodes[2]; TreeNode *node7 = node3->children->nodes[0]; TreeNode *node8 = node3->children->nodes[1]; TreeNode *lmd1 = wm_treenode_lmd(node1); TreeNode *lmd2 = wm_treenode_lmd(node2); TreeNode *lmd3 = wm_treenode_lmd(node3); TreeNode *lmd4 = wm_treenode_lmd(node4); TreeNode *lmd5 = wm_treenode_lmd(node5); TreeNode *lmd6 = wm_treenode_lmd(node6); TreeNode *lmd7 = wm_treenode_lmd(node7); TreeNode *lmd8 = wm_treenode_lmd(node8); assert_non_null(lmd1); assert_non_null(lmd2); assert_non_null(lmd3); assert_non_null(lmd4); assert_non_null(lmd5); assert_non_null(lmd6); assert_non_null(lmd7); assert_non_null(lmd8); assert_ptr_equal(lmd1, node4); assert_ptr_equal(lmd2, node4); assert_ptr_equal(lmd3, node7); assert_ptr_equal(lmd4, node4); assert_ptr_equal(lmd5, node5); assert_ptr_equal(lmd6, node6); assert_ptr_equal(lmd7, node7); assert_ptr_equal(lmd8, node8); } static void test_wm_is_treenode_keyroot(void **state) { TreeNode *node1 = (TreeNode*)*state; NodeArray *postorder = wm_postorder_traversal(node1); assert_non_null(postorder); assert_int_equal(postorder->size, 8); assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[0], postorder), false); assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[1], postorder), true); assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[2], postorder), true); assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[3], postorder), false); assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[4], postorder), false); assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[5], postorder), true); assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[6], postorder), true); assert_int_equal(wm_is_treenode_keyroot(postorder->nodes[7], postorder), true); wm_nodearray_free(postorder); } static void test_wm_treenode_all_lmds(void **state) { TreeNode *node1 = (TreeNode*)*state; NodeArray *lmds = wm_treenode_all_lmds(node1); assert_non_null(lmds); assert_int_equal(lmds->size, 8); assert_int_equal(lmds->nodes[0]->id, 4); assert_int_equal(lmds->nodes[1]->id, 5); assert_int_equal(lmds->nodes[2]->id, 6); assert_int_equal(lmds->nodes[3]->id, 4); assert_int_equal(lmds->nodes[4]->id, 7); assert_int_equal(lmds->nodes[5]->id, 8); assert_int_equal(lmds->nodes[6]->id, 7); assert_int_equal(lmds->nodes[7]->id, 4); wm_nodearray_free(lmds); } static void test_wm_treenode_all_lmds_index(void **state) { TreeNode *node1 = (TreeNode*)*state; NodeArray *postorder = wm_postorder_traversal(node1); UIntArray *lmds = wm_treenode_all_lmds_index(node1); assert_non_null(lmds); assert_int_equal(lmds->size, 8); assert_int_equal(wm_uintarray_at(lmds, 0), 0); assert_int_equal(wm_uintarray_at(lmds, 1), 1); assert_int_equal(wm_uintarray_at(lmds, 2), 2); assert_int_equal(wm_uintarray_at(lmds, 3), 0); assert_int_equal(wm_uintarray_at(lmds, 4), 4); assert_int_equal(wm_uintarray_at(lmds, 5), 5); assert_int_equal(wm_uintarray_at(lmds, 6), 4); assert_int_equal(wm_uintarray_at(lmds, 7), 0); assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 0)], wm_treenode_lmd(postorder->nodes[0])); assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 1)], wm_treenode_lmd(postorder->nodes[1])); assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 2)], wm_treenode_lmd(postorder->nodes[2])); assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 3)], wm_treenode_lmd(postorder->nodes[3])); assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 4)], wm_treenode_lmd(postorder->nodes[4])); assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 5)], wm_treenode_lmd(postorder->nodes[5])); assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 6)], wm_treenode_lmd(postorder->nodes[6])); assert_ptr_equal(postorder->nodes[wm_uintarray_at(lmds, 7)], wm_treenode_lmd(postorder->nodes[7])); wm_nodearray_free(postorder); wm_uintarray_free(lmds); } static void test_wm_treenode_all_keyroots(void **state) { TreeNode *node1 = (TreeNode*)*state; NodeArray *postorder = wm_postorder_traversal(node1); NodeArray *keyroots = wm_treenode_all_keyroots(node1); assert_non_null(keyroots); assert_int_equal(keyroots->size, 5); assert_int_equal(keyroots->nodes[0]->id, 5); assert_int_equal(keyroots->nodes[1]->id, 6); assert_int_equal(keyroots->nodes[2]->id, 8); assert_int_equal(keyroots->nodes[3]->id, 3); assert_int_equal(keyroots->nodes[4]->id, 1); assert_true(wm_is_treenode_keyroot(keyroots->nodes[0], postorder)); assert_true(wm_is_treenode_keyroot(keyroots->nodes[1], postorder)); assert_true(wm_is_treenode_keyroot(keyroots->nodes[2], postorder)); assert_true(wm_is_treenode_keyroot(keyroots->nodes[3], postorder)); assert_true(wm_is_treenode_keyroot(keyroots->nodes[4], postorder)); wm_nodearray_free(postorder); wm_nodearray_free(keyroots); } static void test_wm_treenode_all_keyroots_index(void **state) { TreeNode *node1 = (TreeNode*)*state; NodeArray *postorder = wm_postorder_traversal(node1); UIntArray *keyroot_indexes = wm_treenode_all_keyroots_index(node1); assert_non_null(keyroot_indexes); assert_int_equal(keyroot_indexes->size, 5); assert_int_equal(keyroot_indexes->elements[0], 1); assert_int_equal(keyroot_indexes->elements[1], 2); assert_int_equal(keyroot_indexes->elements[2], 5); assert_int_equal(keyroot_indexes->elements[3], 6); assert_int_equal(keyroot_indexes->elements[4], 7); assert_ptr_equal(postorder->nodes[wm_uintarray_at(keyroot_indexes, 0)], postorder->nodes[1]); assert_ptr_equal(postorder->nodes[wm_uintarray_at(keyroot_indexes, 1)], postorder->nodes[2]); assert_ptr_equal(postorder->nodes[wm_uintarray_at(keyroot_indexes, 2)], postorder->nodes[5]); assert_ptr_equal(postorder->nodes[wm_uintarray_at(keyroot_indexes, 3)], postorder->nodes[6]); assert_ptr_equal(postorder->nodes[wm_uintarray_at(keyroot_indexes, 4)], postorder->nodes[7]); assert_true(wm_is_treenode_keyroot(postorder->nodes[wm_uintarray_at( keyroot_indexes, 0)], postorder)); assert_true(wm_is_treenode_keyroot(postorder->nodes[wm_uintarray_at( keyroot_indexes, 1)], postorder)); assert_true(wm_is_treenode_keyroot(postorder->nodes[wm_uintarray_at( keyroot_indexes, 2)], postorder)); assert_true(wm_is_treenode_keyroot(postorder->nodes[wm_uintarray_at( keyroot_indexes, 3)], postorder)); assert_true(wm_is_treenode_keyroot(postorder->nodes[wm_uintarray_at( keyroot_indexes, 4)], postorder)); wm_nodearray_free(postorder); wm_uintarray_free(keyroot_indexes); } static void test_wm_tree_edit_distance(void **state) { TreeNode *a_root = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *a_child1 = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *a_child2 = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *a_child3 = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *a_child4 = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *a_child5 = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *b_root = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *b_child1 = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *b_child2 = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *b_child3 = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *b_child4 = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *b_child5 = wm_treenode_new(NODE_VERTICAL, NULL); wm_treenode_add_child(a_root, a_child1); wm_treenode_add_child(a_root, a_child2); wm_treenode_add_child(a_child1, a_child3); wm_treenode_add_child(a_child1, a_child4); wm_treenode_add_child(a_child4, a_child5); wm_treenode_add_child(b_root, b_child1); wm_treenode_add_child(b_root, b_child2); wm_treenode_add_child(b_child1, b_child3); wm_treenode_add_child(b_child3, b_child4); wm_treenode_add_child(b_child3, b_child5); size_t dist = wm_tree_edit_distance(a_root, b_root, (TreeEditDistanceCosts) { .insert_cost = 10, .remove_cost = 10, .update_cost_function = &simple_update_cost_function, }); assert_int_equal(dist, 70); wm_treenode_free(a_root); wm_treenode_free(a_child1); wm_treenode_free(a_child2); wm_treenode_free(a_child3); wm_treenode_free(a_child4); wm_treenode_free(a_child5); wm_treenode_free(b_root); wm_treenode_free(b_child1); wm_treenode_free(b_child2); wm_treenode_free(b_child3); wm_treenode_free(b_child4); wm_treenode_free(b_child5); } static int test2_setup(void **state) { TreeNode *node1 = wm_treenode_new(NODE_VERTICAL, NULL); TreeNode *node2 = wm_treenode_new(NODE_VERTICAL, node1); TreeNode *node3 = wm_treenode_new(NODE_VERTICAL, node1); TreeNode *node4 = wm_treenode_new(NODE_VERTICAL, node2); TreeNode *node5 = wm_treenode_new(NODE_VERTICAL, node2); TreeNode *node6 = wm_treenode_new(NODE_VERTICAL, node2); TreeNode *node7 = wm_treenode_new(NODE_VERTICAL, node3); TreeNode *node8 = wm_treenode_new(NODE_VERTICAL, node3); assert_non_null(node1); assert_non_null(node2); assert_non_null(node3); assert_non_null(node4); assert_non_null(node5); assert_non_null(node6); assert_non_null(node7); assert_non_null(node8); wm_treenode_add_child(node1, node2); wm_treenode_add_child(node1, node3); wm_treenode_add_child(node2, node4); wm_treenode_add_child(node2, node5); wm_treenode_add_child(node2, node6); wm_treenode_add_child(node3, node7); wm_treenode_add_child(node3, node8); node1->id = 1; node2->id = 2; node3->id = 3; node4->id = 4; node5->id = 5; node6->id = 6; node7->id = 7; node8->id = 8; assert_null(node1->parent); assert_ptr_equal(node2->parent, node1); assert_ptr_equal(node3->parent, node1); assert_ptr_equal(node4->parent, node2); assert_ptr_equal(node5->parent, node2); assert_ptr_equal(node6->parent, node2); assert_ptr_equal(node7->parent, node3); assert_ptr_equal(node8->parent, node3); assert_int_equal(node1->children->size, 2); assert_int_equal(node2->children->size, 3); assert_int_equal(node3->children->size, 2); assert_int_equal(node1->id, 1); assert_int_equal(node1->children->nodes[0]->id, 2); assert_int_equal(node1->children->nodes[1]->id, 3); assert_int_equal(node2->children->nodes[0]->id, 4); assert_int_equal(node2->children->nodes[1]->id, 5); assert_int_equal(node2->children->nodes[2]->id, 6); assert_int_equal(node3->children->nodes[0]->id, 7); assert_int_equal(node3->children->nodes[1]->id, 8); *state = node1; NodeArray *nodes = wm_all_nodes_to_array((TreeNode*)*state); assert_non_null(nodes); test_group2_nodes_copy = wm_nodearray_new(); for (size_t i = 0; i < nodes->size; i++) { TreeNode *node_copy = malloc(sizeof(TreeNode)); assert_non_null(node_copy); *node_copy = *(nodes->nodes)[i]; wm_nodearray_push(test_group2_nodes_copy, node_copy); } wm_nodearray_free(nodes); return 0; } static int test2_teardown(void **state) { NodeArray *nodes = wm_all_nodes_to_array((TreeNode*)*state); assert_non_null(test_group2_nodes_copy); // check if any of the original nodes were modified for (size_t i = 0; i < test_group2_nodes_copy->size; i++) { TreeNode *node_copy = ((TreeNode**)test_group2_nodes_copy->nodes)[i]; assert_memory_equal(node_copy, nodes->nodes[i], sizeof(TreeNode)); } for (size_t i = 0; i < nodes->size; i++) { wm_treenode_free(nodes->nodes[i]); free((TreeNode*)test_group2_nodes_copy->nodes[i]); } wm_nodearray_free(nodes); wm_nodearray_free(test_group2_nodes_copy); return 0; } static int test1_setup(void **state) { *state = calloc(1, sizeof(TestGroup1State)); TestGroup1State *_state = (TestGroup1State*)(*state); _state->jsonstr = "{" "\"type\":\"NODE_VERTICAL\"," "\"parent\":0," "\"children\":[" "{" "\"type\":\"NODE_CLIENT\"," "\"parent\":105965433127232," "\"children\":[]," "\"pos\":{" "\"x\":2," "\"y\":2," "\"w\":798," "\"h\":896" "}," "\"client\":{" "\"address\":106102872080672," "\"name\":\"child1_client_name\"," "\"is_pid_set\":true," "\"pid\":19058" "}," "\"id\":10" "}," "{" "\"type\":\"NODE_CLIENT\"," "\"parent\":105965433127232," "\"children\":[]," "\"pos\":{" "\"x\":800," "\"y\":2," "\"w\":798," "\"h\":896" "}," "\"client\":{" "\"address\":106102872080800," "\"name\":\"child2_client_name\"," "\"is_pid_set\":true," "\"pid\":19063" "}," "\"id\":11" "}" "]," "\"pos\":{" "\"x\":1," "\"y\":2," "\"w\":3," "\"h\":4" "}," "\"client\":{" "\"address\":1234," "\"name\":\"client_name\"," "\"is_pid_set\":true," "\"pid\":1234" "}," "\"id\":5" "}"; size_t logjsonstr_size = strlen(_state->jsonstr) + 1024; _state->logjsonstr = calloc(logjsonstr_size, 1); snprintf(_state->logjsonstr, logjsonstr_size, "{\"1705601049:wm_kb_spawn:after\": {" "\"2\":" "%s" "}}", _state->jsonstr); const char *basedir = "./"; assert_true(access(basedir, W_OK) >= 0); srand(time(NULL)); bool ok = false; int tries = 0; while (!ok && tries < 1000) { snprintf(_state->logfilepath, PATH_MAX, "%s%ld.json", basedir, random()); if (access(_state->logfilepath, F_OK) < 0) ok = true; tries++; } if (!ok) return 1; int fd = creat(_state->logfilepath, 0664); if (fd < 0) perror("creat"); assert_true(fd >= 0); assert_true(write(fd, _state->logjsonstr, strlen(_state->logjsonstr)) > 0); assert_true(close(fd) >= 0); return 0; } static int test1_teardown(void **state) { TestGroup1State *_state = (TestGroup1State*)(*state); int ret = unlink(_state->logfilepath); if (ret < 0) { perror("unlink"); return 1; } free(_state->logjsonstr); free(*state); return 0; } int main(void) { const struct CMUnitTest test_group1[] = { cmocka_unit_test(test_wm_nodearray_push), cmocka_unit_test(test_wm_treenode_new), cmocka_unit_test(test_wm_treenode_split_space), cmocka_unit_test(test_wm_all_nodes_to_array), cmocka_unit_test(test_wm_find_client_nodes), cmocka_unit_test(test_wm_treenode_remove_client1), cmocka_unit_test(test_wm_treenode_remove_client2), cmocka_unit_test(test_wm_ptrarray_2d_index), cmocka_unit_test(test_wm_treenode_to_str), cmocka_unit_test(test_wm_json_obj_to_treenode), cmocka_unit_test(test_wm_read_log), cmocka_unit_test(test_wm_logentries_calculate_distances), cmocka_unit_test(test_wm_keybind_str_to_mask_keysym), cmocka_unit_test(test_wm_config_parse_bind_command), cmocka_unit_test(test_wm_config), }; const struct CMUnitTest test_group2[] = { cmocka_unit_test(test_wm_postorder_traversal), cmocka_unit_test(test_wm_treenode_lmd), cmocka_unit_test(test_wm_is_treenode_keyroot), cmocka_unit_test(test_wm_treenode_all_lmds), cmocka_unit_test(test_wm_treenode_all_lmds_index), cmocka_unit_test(test_wm_treenode_all_keyroots), cmocka_unit_test(test_wm_treenode_all_keyroots_index), cmocka_unit_test(test_wm_tree_edit_distance), }; cmocka_run_group_tests(test_group1, test1_setup, test1_teardown); cmocka_run_group_tests(test_group2, test2_setup, test2_teardown); }