static void test_random_edits() { // This string should always have the same content as the rope. _string *str = str_create(); rope *r = rope_new(); const size_t max_stringsize = 1000; uint8_t strbuffer[max_stringsize + 1]; for (int i = 0; i < 1000; i++) { // First, some sanity checks. check(r, (char *)str->mem); rope *r2 = rope_copy(r); check(r2, (char *)str->mem); rope_free(r2); // printf("String contains '%s'\n", str->mem); test(rope_byte_count(r) == str->len); size_t len = strlen_utf8(str->mem); test(rope_char_count(r) == len); test(str_num_chars(str) == len); if (len == 0 || rand_float() < 0.5f) { // Insert. //uint8_t *text = random_ascii_string(11); random_unicode_string(strbuffer, 1 + random() % max_stringsize); size_t pos = random() % (len + 1); // printf("inserting %s at %zd\n", strbuffer, pos); rope_insert(r, pos, strbuffer); str_insert(str, pos, strbuffer); } else { // Delete size_t pos = random() % len; size_t dellen = random() % 10; dellen = MIN(len - pos, dellen); // printf("deleting %zd chars at %zd\n", dellen, pos); //deletedText = str[pos...pos + length] //test.strictEqual deletedText, r.substring pos, length rope_del(r, pos, dellen); str_del(str, pos, dellen); } } rope_free(r); str_destroy(str); }
static void test_copy() { // Copy an empty string. rope *r1 = rope_new(); rope *r2 = rope_copy(r1); check(r2, ""); rope_free(r2); // Insert some text (less than one node worth) rope_insert(r1, 0, (uint8_t *)"Eureka!"); r2 = rope_copy(r1); check(r2, "Eureka!"); rope_free(r2); }
// A rope initialized with a string has that string as its content static void test_new_string_has_content() { rope *r = rope_new_with_utf8((uint8_t *)"Hi there"); check(r, "Hi there"); test(rope_char_count(r) == strlen("Hi there")); rope_free(r); // If need be, this could be rewritten as an array of bytes... r = rope_new_with_utf8((uint8_t *)"κόσμε"); check(r, "κόσμε"); test(rope_char_count(r) == 5); rope_insert(r, 2, (uint8_t *)"𝕐𝕆𝌀"); check(r, "κό𝕐𝕆𝌀σμε"); test(rope_char_count(r) == 8); rope_free(r); }
// Create a new rope containing the specified string rope *rope_new_with_utf8(const uint8_t *str) { rope *r = rope_new(); ROPE_RESULT result = rope_insert(r, 0, str); if (result != ROPE_OK) { rope_free(r); return NULL; } else { return r; } }
static void test_custom_allocator() { // Its really hard to test that malloc is never called, but I can make sure // custom frees match custom allocs. rope *r = rope_new2(_alloc, realloc, _free); for (int i = 0; i < 100; i++) { rope_insert(r, random() % (rope_char_count(r) + 1), (uint8_t *)"Whoa super happy fun times!\n"); } rope_free(r); test(alloced_regions == 0); }
static void test_delete_past_end_of_string() { rope *r = rope_new(); rope_del(r, 0, 100); check(r, ""); rope_insert(r, 0, (uint8_t *)"hi there"); rope_del(r, 3, 10); check(r, "hi "); test(rope_char_count(r) == 3); rope_free(r); }
static void test_insert_at_location() { rope *r = rope_new(); rope_insert(r, 0, (uint8_t *)"AAA"); check(r, "AAA"); rope_insert(r, 0, (uint8_t *)"BBB"); check(r, "BBBAAA"); rope_insert(r, 6, (uint8_t *)"CCC"); check(r, "BBBAAACCC"); rope_insert(r, 5, (uint8_t *)"DDD"); check(r, "BBBAADDDACCC"); test(rope_char_count(r) == 12); rope_free(r); }
static void test_really_long_ascii_string() { size_t len = 2000; uint8_t *str = malloc(len + 1); random_ascii_string(str, len + 1); rope *r = rope_new_with_utf8((uint8_t *)str); test(rope_char_count(r) == len); check(r, (char *)str); // Delete everything but the first and last characters. rope_del(r, 1, len - 2); assert(r->num_bytes == 2); assert(r->num_chars == 2); char *contents = (char *)rope_createcstr(r, NULL); _rope_check(r); test(contents[0] == str[0]); test(contents[1] == str[len - 1]); free(contents); rope_free(r); }
static void test_delete_at_location() { rope *r = rope_new_with_utf8((uint8_t *)"012345678"); rope_del(r, 8, 1); check(r, "01234567"); rope_del(r, 0, 1); check(r, "1234567"); rope_del(r, 5, 1); check(r, "123457"); rope_del(r, 5, 1); check(r, "12345"); rope_del(r, 0, 5); check(r, ""); test(rope_char_count(r) == 0); rope_free(r); }
static void test_empty_rope_has_no_content() { rope *r = rope_new(); check(r, ""); test(rope_char_count(r) == 0); rope_free(r); }