#include "test_dbuf.hpp" extern "C" { #include "guf_alloc_libc.h" #include "impls/dbuf_impl.h" } /* DbufIntTest */ void DbufIntTest::run() { if (done) { return; } dbuf_int dbuf {}; dbuf_int_init(&dbuf, 0, &guf_allocator_libc); push_check_name("test_push"); test_push(&dbuf, 256); test_push(&dbuf, 128); test_push(&dbuf, 17); TEST_CHECK(dbuf.size == (256 + 128 + 17)); dbuf_int_free(&dbuf, NULL); TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && dbuf.data == NULL); dbuf_int_init(&dbuf, 24, &guf_allocator_libc); TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 24 && dbuf.data); test_push(&dbuf, 365); test_push(&dbuf, 4); test_push(&dbuf, 25); test_push(&dbuf, 64); TEST_CHECK(dbuf.size == (365 + 4 + 25 + 64)); dbuf_int_free(&dbuf, NULL); TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && dbuf.data == NULL); pop_check_name(); push_check_name("insert_remove"); for (int n = 0; n <= 128; ++n) { test_insert_remove(n); } test_insert_remove(400); test_insert_remove(401); test_insert_remove(512); test_insert_remove(513); test_insert_remove(601); test_insert_remove(2048); test_insert_remove(2049); pop_check_name(); } std::vector DbufIntTest::dbuf_to_vec(dbuf_int *dbuf) { std::vector vec; GUF_CNT_FOREACH(dbuf, dbuf_int, it) { vec.push_back(*it.ptr); } return vec; } void DbufIntTest::test_push(dbuf_int *dbuf, int n) { std::vector vec = dbuf_to_vec(dbuf); TEST_CHECK(std::ssize(vec) == dbuf->size); for (int i = 0; i < n; ++i) { dbuf_int_push_val(dbuf, i); vec.push_back(i); TEST_CHECK(*dbuf_int_back(dbuf) == vec.back()); } ptrdiff_t i = 0; GUF_CNT_FOREACH(dbuf, dbuf_int, it) { TEST_CHECK(*it.ptr == vec.at(i++)); } TEST_CHECK(i == dbuf->size); i = dbuf->size - 1; GUF_CNT_FOREACH_REVERSE(dbuf, dbuf_int, rit) { TEST_CHECK(*rit.ptr == vec.at(i--)); } TEST_CHECK(i == -1); } void DbufIntTest::test_insert_remove(int n) { dbuf_int dbuf = {}; dbuf_int_init(&dbuf, 0, &guf_allocator_libc); std::vector vec = dbuf_to_vec(&dbuf); guf_err err = GUF_ERR_NONE; dbuf_int_try_erase(&dbuf, 0, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_int_try_erase(&dbuf, 12, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_int_try_front(&dbuf, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_int_try_back(&dbuf, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_int_try_at(&dbuf, 0, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); for (int i = 0; i < n; ++i) { dbuf_int_insert_val(&dbuf, i, i); dbuf_int_insert_val(&dbuf, i * 2, 0); dbuf_int_insert_val(&dbuf, i * 4, dbuf.size); vec.insert(vec.begin() + i, i); vec.insert(vec.begin(), i * 2); vec.insert(vec.end(), i * 4); } TEST_CHECK(std::ssize(vec) == dbuf.size); // Iterate dbuf_int_iter it_dbuf = dbuf_int_begin(&dbuf); std::vector::const_iterator it_vec = vec.begin(); while (!dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec != vec.end()) { TEST_CHECK(*it_dbuf.ptr == *it_vec); it_dbuf = dbuf_int_iter_next(&dbuf, it_dbuf, 1); std::advance(it_vec, 1); } TEST_CHECK(dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec == vec.end()); // Step iterate. it_dbuf = dbuf_int_begin(&dbuf); it_vec = vec.begin(); while (!dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec != vec.end()) { TEST_CHECK(*it_dbuf.ptr == *it_vec); it_dbuf = dbuf_int_iter_next(&dbuf, it_dbuf, 7); if (dbuf_int_iter_is_end(&dbuf, it_dbuf)) { it_vec = vec.end(); } else { std::advance(it_vec, 7); } } TEST_CHECK(dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec == vec.end()); // Reverse iterate. dbuf_int_iter rit_dbuf = dbuf_int_rbegin(&dbuf); std::vector::const_reverse_iterator rit_vec = vec.crbegin(); while (!dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec != vec.crend()) { TEST_CHECK(*rit_dbuf.ptr == *rit_vec); rit_dbuf = dbuf_int_iter_next(&dbuf, rit_dbuf, 1); std::advance(rit_vec, 1); } TEST_CHECK(dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec == vec.rend()); // Reverse iterate step. rit_dbuf = dbuf_int_rbegin(&dbuf); rit_vec = vec.crbegin(); while (!dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec != vec.crend()) { TEST_CHECK(*rit_dbuf.ptr == *rit_vec); rit_dbuf = dbuf_int_iter_next(&dbuf, rit_dbuf, 4); if (dbuf_int_iter_is_end(&dbuf, rit_dbuf)) { rit_vec = vec.rend(); } else { std::advance(rit_vec, 4); } } TEST_CHECK(dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec == vec.rend()); TEST_CHECK(dbuf.size == std::ssize(vec)); for (ptrdiff_t i = 0; i < dbuf.size; i += 8) { dbuf_int_erase(&dbuf, i); dbuf_int_erase(&dbuf, 0); dbuf_int_pop(&dbuf); vec.erase(vec.begin() + i); vec.erase(vec.begin() + 0); vec.pop_back(); } TEST_CHECK(dbuf.size == std::ssize(vec)); for (ptrdiff_t i = 0; i < dbuf.size; i += 8) { TEST_CHECK(*dbuf_int_at(&dbuf, i) == vec.at(i)); } const ptrdiff_t size = dbuf.size; for (ptrdiff_t i = 0; i < size; ++i) { int a = dbuf_int_pop_move(&dbuf); int b = vec.back(); TEST_CHECK(a == b); vec.pop_back(); } TEST_CHECK(dbuf.size == 0 && vec.size() == 0); dbuf_int_free(&dbuf, NULL); TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && !dbuf.data); } /* DbufCstringTest */ void DbufCstringTest::run() { if (done) { return; } push_check_name("push_insert_erase"); for (int i = 1; i <= 32; ++i) { test_push_insert_erase(i); test_push_insert_erase(i, i - 1); test_push_insert_erase(i, i + 1); test_push_insert_erase(i, i); test_push_insert_erase(i, i / 2); } test_push_insert_erase(2048); test_push_insert_erase(2048, 11); dbuf_heap_cstr str_dbuf = {}; dbuf_heap_cstr_init(&str_dbuf, 0, &guf_allocator_libc); std::vector str_vec {}; for (int i = 0; i < 512; ++i) { char buf[128]; memset(buf, '\0', GUF_ARR_SIZE(buf)); snprintf(buf, GUF_ARR_SIZE(buf), "This is a pretty guf string (number %d)", i); guf_cstr_heap str = buf; dbuf_heap_cstr_push(&str_dbuf, &str, GUF_CPY_DEEP); str_vec.push_back(std::string{buf}); } for (int i = 0; i < str_dbuf.size + 16; ++i) { test_iter(str_vec, &str_dbuf, i); } dbuf_heap_cstr_free(&str_dbuf, NULL); TEST_CHECK(str_dbuf.size == 0 && str_dbuf.capacity == 0 && !str_dbuf.data); pop_check_name(); push_check_name("find"); test_find(); test_find(3); test_find(42); test_find(129); pop_check_name(); } void DbufCstringTest::test_iter(std::vector& str_vec, dbuf_heap_cstr *str_dbuf, int step) { GUF_ASSERT_RELEASE(str_dbuf); if (step <= 0) { step = 1; } ptrdiff_t i = 0; GUF_CNT_FOREACH(str_dbuf, dbuf_heap_cstr, it) { char *str = *it.ptr; TEST_CHECK(str_vec.at(i) == str); ++i; } TEST_CHECK(i == str_dbuf->size); i = str_dbuf->size - 1; GUF_CNT_FOREACH_REVERSE(str_dbuf, dbuf_heap_cstr, rit) { char *str = *rit.ptr; TEST_CHECK(str_vec.at(i) == str); --i; } TEST_CHECK(i == -1); dbuf_heap_cstr_iter it_dbuf = dbuf_heap_cstr_begin(str_dbuf); std::vector::iterator it_vec = str_vec.begin(); while (!dbuf_heap_cstr_iter_is_end(str_dbuf, it_dbuf)) { TEST_CHECK(it_vec != str_vec.end()); TEST_CHECK(*it_vec == *it_dbuf.ptr); it_dbuf = dbuf_heap_cstr_iter_next(str_dbuf, it_dbuf, step); if (!dbuf_heap_cstr_iter_is_end(str_dbuf, it_dbuf)) { std::advance(it_vec, step); } else { it_vec = str_vec.end(); } } TEST_CHECK(dbuf_heap_cstr_iter_is_end(str_dbuf, it_dbuf) && it_vec == str_vec.end()); dbuf_heap_cstr_iter rit_dbuf = dbuf_heap_cstr_rbegin(str_dbuf); std::vector::reverse_iterator rit_vec = str_vec.rbegin(); while (!dbuf_heap_cstr_iter_is_end(str_dbuf, rit_dbuf)) { TEST_CHECK(rit_vec != str_vec.rend()); TEST_CHECK(*rit_vec == *rit_dbuf.ptr); rit_dbuf = dbuf_heap_cstr_iter_next(str_dbuf, rit_dbuf, step); if (!dbuf_heap_cstr_iter_is_end(str_dbuf, rit_dbuf)) { std::advance(rit_vec, step); } else { rit_vec = str_vec.rend(); } } TEST_CHECK(dbuf_heap_cstr_iter_is_end(str_dbuf, rit_dbuf) && rit_vec == str_vec.rend()); for (i = 0; i < str_dbuf->size; ++i) { char *str = *dbuf_heap_cstr_at(str_dbuf, i); TEST_CHECK(str_vec.at(i) == str); } } void DbufCstringTest::test_push_insert_erase(int n, ptrdiff_t start_cap) { std::vector str_vec; dbuf_heap_cstr str_dbuf {}; dbuf_heap_cstr_init(&str_dbuf, start_cap, &guf_allocator_libc); for (int i = 0; i < n; ++i) { constexpr int BUF_SZ = 128; char buf[BUF_SZ]; memset(buf, '\0', BUF_SZ); snprintf(buf, BUF_SZ, "This is string number %d", i); guf_cstr_heap str = buf; dbuf_heap_cstr_push(&str_dbuf, &str, GUF_CPY_DEEP); dbuf_heap_cstr_push_val_cpy(&str_dbuf, str); char *heap_buf = strdup("Move me plz"); dbuf_heap_cstr_push(&str_dbuf, &heap_buf, GUF_CPY_MOVE); TEST_CHECK(heap_buf == NULL); TEST_CHECK(strncmp(*dbuf_heap_cstr_back(&str_dbuf), "Move me plz", BUF_SZ) == 0); TEST_CHECK(strncmp(*dbuf_heap_cstr_at(&str_dbuf, str_dbuf.size - 2), buf, BUF_SZ) == 0); TEST_CHECK(strncmp(*dbuf_heap_cstr_at(&str_dbuf, str_dbuf.size - 3), buf, BUF_SZ) == 0); str_vec.push_back(std::string{buf}); str_vec.push_back(std::string{buf}); str_vec.emplace_back("Move me plz"); } TEST_CHECK(str_dbuf.size == std::ssize(str_vec)); TEST_CHECK(str_dbuf.size == 3 * n); for (int i = 1; i <= 8; ++i) { test_iter(str_vec, &str_dbuf, i); } test_iter(str_vec, &str_dbuf, str_dbuf.size); test_iter(str_vec, &str_dbuf, str_dbuf.size - 1); test_iter(str_vec, &str_dbuf, str_dbuf.size + 1); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i)); } // Insert front. for (ptrdiff_t i = 0; i < 16; ++i) { char str[] = "front"; dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, 0); str_vec.insert(str_vec.begin(), std::string{str}); } TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i)); } // Insert back. for (ptrdiff_t i = 0; i < 16; ++i) { char str[] = "front"; dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size); str_vec.insert(str_vec.end(), std::string{str}); } TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i)); } // Insert at i. char str[] = "guf"; dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size / 2); str_vec.insert(str_vec.begin() + str_vec.size() / 2, str); dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size / 4); str_vec.insert(str_vec.begin() + str_vec.size() / 4, str); dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, 1); str_vec.insert(str_vec.begin() + 1, str); dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size - 1); str_vec.insert(str_vec.begin() + (str_vec.size() - 1), str); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i)); } guf_err err = GUF_ERR_NONE; dbuf_heap_cstr_try_insert_val_cpy(&str_dbuf, str, str_dbuf.size + 1, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_heap_cstr_try_insert_val_cpy(&str_dbuf, str, -1, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); err = GUF_ERR_NONE; dbuf_heap_cstr_try_insert_val_cpy(&str_dbuf, str, str_dbuf.size + 2, &err); TEST_CHECK(err == GUF_ERR_IDX_RANGE); TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i)); } if (str_dbuf.size) { dbuf_heap_cstr_erase(&str_dbuf, str_dbuf.size - 1); str_vec.erase(str_vec.end() - 1); } ptrdiff_t to_rem = 8; while (str_dbuf.size && to_rem--) { dbuf_heap_cstr_erase(&str_dbuf, 0); str_vec.erase(str_vec.begin()); TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); if (str_dbuf.size) { dbuf_heap_cstr_pop(&str_dbuf); str_vec.pop_back(); TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); } if (str_dbuf.size) { dbuf_heap_cstr_erase(&str_dbuf, str_dbuf.size / 2); str_vec.erase(str_vec.begin() + (str_vec.size() / 2)); TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); } } dbuf_heap_cstr_free(&str_dbuf, NULL); TEST_CHECK(str_dbuf.size == 0 && str_dbuf.capacity == 0 && !str_dbuf.data); } void DbufCstringTest::test_find(int n) { if (n < 2) { n = 2; } std::vector str_vec {}; dbuf_heap_cstr str_dbuf = {}; dbuf_heap_cstr_init(&str_dbuf, 0, &guf_allocator_libc); for (int i = 0; i < n; ++i) { constexpr int BUF_SZ = 128; char buf[BUF_SZ]; memset(buf, '\0', BUF_SZ); snprintf(buf, BUF_SZ, "String number %d", i); dbuf_heap_cstr_push_val_cpy(&str_dbuf, buf); str_vec.push_back(buf); } char *move_me = strdup("Moved string"); dbuf_heap_cstr_push(&str_dbuf, &move_me, GUF_CPY_MOVE); GUF_ASSERT_RELEASE(move_me == NULL); str_vec.emplace_back("Moved string"); TEST_CHECK(std::ssize(str_vec) == str_dbuf.size); for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) { char *needle = *dbuf_heap_cstr_at(&str_dbuf, i); TEST_CHECK(str_vec.at(i) == needle); TEST_CHECK(dbuf_heap_cstr_contains_val(&str_dbuf, needle)); dbuf_heap_cstr_iter fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), dbuf_heap_cstr_end(&str_dbuf), needle); TEST_CHECK(!dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin(), str_vec.cend(), needle) != str_vec.end()); dbuf_heap_cstr_iter begin = dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), i); dbuf_heap_cstr_iter end = dbuf_heap_cstr_end(&str_dbuf); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, begin, end, needle); TEST_CHECK(!dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin() + i, str_vec.cend(), needle) != str_vec.end()); begin = dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), i + 1); end = dbuf_heap_cstr_end(&str_dbuf); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, begin, end, needle); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin() + i + 1, str_vec.cend(), needle) == str_vec.end()); // Reverse. fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_rbegin(&str_dbuf), dbuf_heap_cstr_rend(&str_dbuf), needle); TEST_CHECK(!dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.crbegin(), str_vec.crend(), needle) != str_vec.rend()); } char needle[] = "Definitely not inside"; dbuf_heap_cstr_iter fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), dbuf_heap_cstr_end(&str_dbuf), needle); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin(), str_vec.cend(), needle) == str_vec.end()); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_rbegin(&str_dbuf), dbuf_heap_cstr_rend(&str_dbuf), needle); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.crbegin(), str_vec.crend(), needle) == str_vec.rend()); char *needle2 = *dbuf_heap_cstr_at(&str_dbuf, 0); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), 1), dbuf_heap_cstr_end(&str_dbuf), needle2); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin() + 1, str_vec.cend(), needle2) == str_vec.end()); needle2 = *dbuf_heap_cstr_back(&str_dbuf); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), 1), dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_end(&str_dbuf), -1), needle2); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.begin(), str_vec.end() - 1, needle2) == (str_vec.end() - 1)); needle2 = *dbuf_heap_cstr_at(&str_dbuf, 0); fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), dbuf_heap_cstr_begin(&str_dbuf), needle2); TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it)); TEST_CHECK(std::find(str_vec.cbegin(), str_vec.cbegin(), needle2) == str_vec.cbegin()); dbuf_heap_cstr_free(&str_dbuf, NULL); }