#include #ifdef main #undef main #endif #define main dat_thang_program_main #include "../src/ddat_gui.c" #undef main #include #include #include #include #ifdef _WIN32 #include #include #define test_getpid _getpid #define test_mkdir(path) _mkdir(path) #define test_setenv(name, value) _putenv_s((name), (value)) #else #include #include #define test_getpid getpid #define test_mkdir(path) mkdir(path, 0700) #define test_setenv(name, value) setenv((name), (value), 1) #endif int main(void) { static gui_state_t state; dat_archive_t first, second; char test_root[256], first_path[300], second_path[300]; char first_key[65], second_key[65]; int n, fixture_attempt; setvbuf(stdout, NULL, _IONBF, 0); memset(&state, 0, sizeof(state)); state.archive_open = 1; state.version = 12; state.selected_version = 12; /* The displayed left/right halves of the version field are click targets. */ assert(click_archive_version_bar(&state, 210, 74, 84)); assert(state.selected_version == 11); assert(click_archive_version_bar(&state, 226, 93, 84)); assert(state.selected_version == 12); assert(click_archive_version_bar(&state, 226, 80, 84)); assert(state.selected_version == 12); /* clamp at latest */ assert(!click_archive_version_bar(&state, 209, 80, 84)); assert(!click_archive_version_bar(&state, 242, 80, 84)); assert(!click_archive_version_bar(&state, 210, 73, 84)); assert(!click_archive_version_bar(&state, 210, 94, 84)); state.archive_open = 0; assert(!click_archive_version_bar(&state, 210, 80, 84)); puts("dat-thang version bar hitbox and bounds: PASS"); /* The visible version is the number of metadata entries after the feed * header, while the Merkle tree counts every block including that header. */ assert(merkle_version_block_count(0, 0) == 1); assert(merkle_version_block_count(3, 0) == 1); assert(merkle_version_block_count(3, 2) == 3); assert(merkle_version_block_count(3, 99) == 4); { uint64_t roots[4]; assert(sleep_tree_full_roots(3 * 2, roots, 4) == 2); assert(roots[0] == 1 && roots[1] == 4); } puts("dat-thang Merkle view uses the selected SLEEP feed blocks: PASS"); /* Regression: browsing to another directory must not erase the loaded * archive's address during the one-second archive refresh. */ for (fixture_attempt = 0; fixture_attempt < 1000; fixture_attempt++) { n = snprintf(test_root, sizeof(test_root), "build/test-version-bar-%ld-%d", (long)test_getpid(), fixture_attempt); assert(n > 0 && (size_t)n < sizeof(test_root)); if (test_mkdir(test_root) == 0) break; } assert(fixture_attempt < 1000); assert(test_setenv("USERPROFILE", test_root) == 0); #ifdef _WIN32 assert(test_setenv("HOME", "") == 0); #else assert(test_setenv("HOME", test_root) == 0); #endif { char path[1024]; strcpy(path, "."); assert(parent_directory(path, sizeof(path)) == 1); assert(strcmp(path, ".") != 0); #ifdef _WIN32 char cwd[1024]; assert(_getcwd(cwd, sizeof(cwd)) != NULL); snprintf(path, sizeof(path), "%c:\\", cwd[0]); #else strcpy(path, "/"); #endif assert(parent_directory(path, sizeof(path)) == 0); } puts("dat-thang directory browser resolves relative parents and stops at root: PASS"); n = snprintf(first_path, sizeof(first_path), "%s/first", test_root); assert(n > 0 && (size_t)n < sizeof(first_path)); n = snprintf(second_path, sizeof(second_path), "%s/second", test_root); assert(n > 0 && (size_t)n < sizeof(second_path)); assert(test_mkdir(first_path) == 0 && test_mkdir(second_path) == 0); assert(dat_archive_create(&first, first_path) == 0); assert(dat_archive_create(&second, second_path) == 0); memset(&state, 0, sizeof(state)); snprintf(state.shared_paths[0], sizeof(state.shared_paths[0]), "%s", first_path); snprintf(state.shared_paths[1], sizeof(state.shared_paths[1]), "%s", second_path); state.shared_path_count = 2; assert(select_shared_archive(&state, 0) == 0); assert(state.archive_open && !strcmp(state.archive_path, first_path)); assert(state.shared_path_count == 2); assert(!strcmp(state.shared_paths[0], first_path)); assert(!strcmp(state.shared_paths[1], second_path)); puts("dat-thang right-click archive selection preserves the shared list: PASS"); assert(dat_key_to_hex(first.metadata_key, first_key) == 0); assert(dat_key_to_hex(second.metadata_key, second_key) == 0); assert(strcmp(first_key, second_key) != 0); dat_archive_close(&first); dat_archive_close(&second); memset(&state, 0, sizeof(state)); state.identity_valid = 1; memset(&state.identity, 0x5a, sizeof(state.identity)); snprintf(state.archive_path, sizeof(state.archive_path), "%s", first_path); refresh_archive(&state); assert(state.archive_open && !strcmp(state.archive_key, first_key)); assert(state.identity_valid); for (size_t i = 0; i < sizeof(state.identity); i++) assert(((const unsigned char *)&state.identity)[i] == 0x5a); strcpy(state.site_name, "first.example.test"); state.site_name_editing = 1; assert(save_site_name(&state) == 0); state.site_name_editing = 0; { uint8_t resolved[DAT_KEY_BYTES]; assert(dat_dns_resolve("first.example.test", resolved, NULL) == 0); assert(!memcmp(resolved, state.archive_key_bytes, sizeof(resolved))); } snprintf(state.archive_path, sizeof(state.archive_path), "%s", second_path); refresh_archive_at(&state, state.archive_loaded_path); assert(state.archive_open && !strcmp(state.archive_key, first_key)); assert(!strcmp(state.archive_path, second_path)); assert(!strcmp(state.site_name, "first.example.test")); refresh_archive(&state); assert(state.archive_open && !strcmp(state.archive_key, second_key)); assert(!state.site_name[0]); assert(dat_dns_name_remove("first.example.test") == 0); puts("dat-thang selected archive address survives browsing: PASS"); puts("dat-thang SITE alias persists to its archive key: PASS"); assert(test_setenv("CABLE_THANG_MANPAGE", "") == 0); state.cable_thang_mode = 1; load_manpage(&state); { int found = 0; for (int line = 0; line < state.help_count; line++) if (strstr(state.help_lines[line], "SDL2 Cable room chat client")) found = 1; assert(found); } puts("cable-thang F1 loads the Cable manual: PASS"); return 0; }