From 176948356dfe02f6217ad432316c4fa51fc933f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Sat, 18 Feb 2017 16:14:28 +0100 Subject: test/core: rename files to have distinct names Having different names for the test driver/actual implementation might make the Travis / Codecov errors less confusing. --- core/.gitignore | 8 +-- core/Makefile | 23 +++--- core/array-test.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++ core/array.c | 207 ----------------------------------------------------- core/buffer-test.c | 90 +++++++++++++++++++++++ core/buffer.c | 90 ----------------------- core/map-test.c | 115 +++++++++++++++++++++++++++++ core/map.c | 115 ----------------------------- core/text-test.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++ core/text.c | 204 ---------------------------------------------------- 10 files changed, 630 insertions(+), 633 deletions(-) create mode 100644 core/array-test.c delete mode 100644 core/array.c create mode 100644 core/buffer-test.c delete mode 100644 core/buffer.c create mode 100644 core/map-test.c delete mode 100644 core/map.c create mode 100644 core/text-test.c delete mode 100644 core/text.c diff --git a/core/.gitignore b/core/.gitignore index f14cb69..b5fdb76 100644 --- a/core/.gitignore +++ b/core/.gitignore @@ -1,8 +1,8 @@ /config.h -/text -/buffer -/map -/array +/text-test +/buffer-test +/map-test +/array-test /ccan-config *.gcda *.gcno diff --git a/core/Makefile b/core/Makefile index 9773846..26f7fcf 100644 --- a/core/Makefile +++ b/core/Makefile @@ -1,32 +1,32 @@ -include ../../config.mk -ALL = buffer map array text +ALL = buffer-test map-test array-test text-test SRC = $(wildcard ccan/*/*.c) CFLAGS += -I. -I../.. -DBUFFER_SIZE=4 -DBLOCK_SIZE=4 test: $(ALL) - @./buffer - @./map - @./array - @./text + @./buffer-test + @./map-test + @./array-test + @./text-test config.h: @echo Generating ccan configuration header @${CC} ccan-config.c -o ccan-config && ./ccan-config > config.h -text: config.h text.c ../../text.c ../../text-util.c ../../text-motions.c ../../text-objects.c ../../text-regex.c +text-test: config.h text-test.c ../../text.c ../../text-util.c ../../text-motions.c ../../text-objects.c ../../text-regex.c @echo Compiling $@ binary @${CC} ${CFLAGS} ${CFLAGS_STD} ${CFLAGS_EXTRA} ${filter %.c, $^} ${SRC} ${LDFLAGS} -o $@ -buffer: config.h buffer.c ../../buffer.c +buffer-test: config.h buffer-test.c ../../buffer.c @echo Compiling $@ binary @${CC} ${CFLAGS} ${CFLAGS_STD} ${CFLAGS_EXTRA} ${filter %.c, $^} ${SRC} ${LDFLAGS} -o $@ -map: config.h map.c ../../map.c +map-test: config.h map-test.c ../../map.c @echo Compiling $@ binary @${CC} ${CFLAGS} ${CFLAGS_STD} ${CFLAGS_EXTRA} ${filter %.c, $^} ${SRC} ${LDFLAGS} -o $@ -array: config.h array.c ../../array.c +array-test: config.h array-test.c ../../array.c @echo Compiling $@ binary @${CC} ${CFLAGS} ${CFLAGS_STD} ${CFLAGS_EXTRA} ${filter %.c, $^} ${SRC} ${LDFLAGS} -o $@ @@ -54,10 +54,7 @@ tis: clean clean: @echo cleaning - @rm -f buffer - @rm -f map - @rm -f array - @rm -f text + @rm -f $(ALL) @rm -f *.gcov *.gcda *.gcno @rm -f *.valgrind diff --git a/core/array-test.c b/core/array-test.c new file mode 100644 index 0000000..5cf19a6 --- /dev/null +++ b/core/array-test.c @@ -0,0 +1,207 @@ +#include +#include +#include +#include +#include +#include +#include "tap.h" +#include "array.h" +#include "../../util.h" + +typedef struct { + char key[64]; + int value; +} Item; + +static int values[] = { 2, 3, 5, 7, 11 }; +static const size_t len = LENGTH(values); + +static bool item_compare(Item *a, Item *b) { + return strcmp(a->key, b->key) == 0 && a->value == b->value; +} + +static void test_small_objects(void) { + Array arr; + array_init_sized(&arr, sizeof(int)); + ok(array_length(&arr) == 0, "Initialization"); + ok(!array_set(&arr, 0, NULL) && errno == EINVAL, "Set with invalid index"); + ok(array_get(&arr, 0) == NULL && errno == EINVAL, "Get with invalid index"); + + for (size_t i = 0; i < len; i++) { + int *v; + ok(array_add(&arr, &values[i]) && array_length(&arr) == i+1, + "Add integer: %zu = %d", i, values[i]); + ok((v = array_get(&arr, i)) && *v == values[i], + "Get integer: %zu = %d", i, *v); + } + + for (size_t i = 0; i < len; i++) { + ok(array_set(&arr, i, &values[len-i-1]) && array_length(&arr) == len, + "Set array element: %zu = %d", i, values[len-i-1]); + } + + for (size_t i = 0; i < len; i++) { + int *v; + ok((v = array_get(&arr, i)) && *v == values[len-i-1], + "Get array element: %zu = %d", i, *v); + } + + array_clear(&arr); + ok(array_length(&arr) == 0 && array_get(&arr, 0) == NULL && errno == EINVAL, "Clear"); + + for (size_t i = 0; i < len; i++) { + ok(array_add(&arr, &values[i]) && array_length(&arr) == i+1, + "Re-add integer: %zu = %d", i, values[i]); + } + + int old, *tmp; + ok((tmp = array_get(&arr, 0)) && (old = *tmp) && array_set(&arr, 0, NULL) && + array_get(&arr, 0) == tmp && *tmp == 0 && array_set(&arr, 0, &old) && + array_get(&arr, 0) == tmp && *tmp == old, "Set array element NULL"); + ok(!array_set(&arr, array_length(&arr), &values[0]) && errno == EINVAL, "Get past end of array"); + ok(!array_get(&arr, array_length(&arr)) && errno == EINVAL, "Get past end of array"); + + ok(!array_remove(&arr, array_length(&arr)) && errno == EINVAL, "Remove past end of array"); + + int *v; + + size_t len_before = array_length(&arr); + ok(array_remove(&arr, 2) && array_length(&arr) == len_before-1 && + (v = array_get(&arr, 0)) && *v == values[0] && + (v = array_get(&arr, 1)) && *v == values[1] && + (v = array_get(&arr, 2)) && *v == values[3] && + (v = array_get(&arr, 3)) && *v == values[4], + "Remove element 2"); + + len_before = array_length(&arr); + ok(array_remove(&arr, 0) && array_length(&arr) == len_before-1 && + (v = array_get(&arr, 0)) && *v == values[1] && + (v = array_get(&arr, 1)) && *v == values[3] && + (v = array_get(&arr, 2)) && *v == values[4], + "Remove first element"); + + len_before = array_length(&arr); + ok(array_remove(&arr, len_before-1) && array_length(&arr) == len_before-1 && + (v = array_get(&arr, 0)) && *v == values[1] && + (v = array_get(&arr, 1)) && *v == values[3], + "Remove last element"); + + array_release(&arr); +} + +static void test_large_objects(void) { + Array arr; + array_init_sized(&arr, sizeof(Item)); + ok(array_length(&arr) == 0 && array_get(&arr, 0) == NULL && errno == EINVAL, + "Initialization"); + + Item items[len]; + + for (size_t i = 0; i < len; i++) { + snprintf(items[i].key, sizeof items[i].key, "key: %zu", i); + items[i].value = values[i]; + Item *item; + ok(array_add(&arr, &items[i]) && array_length(&arr) == i+1, + "Add item: %zu = { '%s' = %d }", i, items[i].key, items[i].value); + ok((item = array_get(&arr, i)) && item != &items[i] && item_compare(item, &items[i]), + "Get item: %zu = { '%s' = %d }", i, item->key, item->value); + } + + for (size_t i = 0; i < len; i++) { + Item *item = &items[len-i-1]; + ok(array_set(&arr, i, item) && array_length(&arr) == len, + "Set array element: %zu = { '%s' = %d }", i, item->key, item->value); + } + + for (size_t i = 0; i < len; i++) { + Item *item; + ok((item = array_get(&arr, i)) && item != &items[len-i-1] && item_compare(item, &items[len-i-1]), + "Get item: %zu = { '%s' = %d }", i, item->key, item->value); + } + + ok(!array_add_ptr(&arr, &items[0]) && errno == ENOTSUP && array_length(&arr) == len, + "Adding pointer to non pointer array"); + ok(!array_set_ptr(&arr, 0, &items[0]) && errno == ENOTSUP && item_compare(array_get(&arr, 0), &items[len-1]), + "Setting pointer in non pointer array"); + + array_clear(&arr); + ok(array_length(&arr) == 0 && array_get(&arr, 0) == NULL && errno == EINVAL, "Clear"); + + array_release(&arr); +} + +static void test_pointers(void) { + + Array arr; + + array_init_sized(&arr, 1); + ok(array_length(&arr) == 0 && array_get_ptr(&arr, 0) == NULL && errno == ENOTSUP, + "Initialization with size 1"); + + ok(!array_add_ptr(&arr, &arr) && errno == ENOTSUP && array_get_ptr(&arr, 0) == NULL, + "Add pointer to non-pointer array"); + + errno = 0; + char byte = '_', *ptr; + ok(array_add(&arr, &byte) && (ptr = array_get(&arr, 0)) && *ptr == byte, + "Add byte element"); + ok(!array_get_ptr(&arr, 0) && errno == ENOTSUP, "Get pointer from non-pointer array"); + + array_init(&arr); + ok(array_length(&arr) == 0 && array_get_ptr(&arr, 0) == NULL && errno == EINVAL, + "Initialization"); + + Item *items[len]; + + for (size_t i = 0; i < len; i++) { + items[i] = malloc(sizeof(Item)); + snprintf(items[i]->key, sizeof(items[i]->key), "key: %zu", i); + items[i]->value = values[i]; + } + + for (size_t i = 0; i < len; i++) { + Item *item; + ok(array_add_ptr(&arr, items[i]) && array_length(&arr) == i+1, + "Add item: %zu = %p", i, (void*)items[i]); + ok((item = array_get_ptr(&arr, i)) && item == items[i], + "Get item: %zu = %p", i, (void*)item); + } + + for (size_t i = 0; i < len; i++) { + Item *item = items[len-i-1]; + ok(array_set_ptr(&arr, i, item) && array_length(&arr) == len, + "Set item: %zu = %p", i, (void*)item); + } + + for (size_t i = 0; i < len; i++) { + Item *item; + ok((item = array_get_ptr(&arr, i)) && item == items[len-i-1], + "Get item: %zu = %p", i, (void*)item); + } + + Item *tmp; + ok((tmp = array_get_ptr(&arr, 0)) && array_set_ptr(&arr, 0, NULL) && + array_get_ptr(&arr, 0) == NULL && array_set_ptr(&arr, 0, tmp) && + array_get_ptr(&arr, 0) == tmp, "Set pointer NULL"); + ok(!array_set_ptr(&arr, array_length(&arr), items[0]) && errno == EINVAL, "Set pointer past end of array"); + ok(!array_get_ptr(&arr, array_length(&arr)) && errno == EINVAL, "Get pointer past end of array"); + + array_clear(&arr); + ok(array_length(&arr) == 0 && array_get_ptr(&arr, 0) == NULL && errno == EINVAL, "Clear"); + + for (size_t i = 0; i < len; i++) { + ok(array_add_ptr(&arr, items[i]) && array_length(&arr) == i+1, + "Re-add item: %zu = %p", i, (void*)items[i]); + } + array_release_full(&arr); +} + +int main(int argc, char *argv[]) { + plan_no_plan(); + + test_small_objects(); + test_large_objects(); + test_pointers(); + + return exit_status(); +} diff --git a/core/array.c b/core/array.c deleted file mode 100644 index 5cf19a6..0000000 --- a/core/array.c +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "tap.h" -#include "array.h" -#include "../../util.h" - -typedef struct { - char key[64]; - int value; -} Item; - -static int values[] = { 2, 3, 5, 7, 11 }; -static const size_t len = LENGTH(values); - -static bool item_compare(Item *a, Item *b) { - return strcmp(a->key, b->key) == 0 && a->value == b->value; -} - -static void test_small_objects(void) { - Array arr; - array_init_sized(&arr, sizeof(int)); - ok(array_length(&arr) == 0, "Initialization"); - ok(!array_set(&arr, 0, NULL) && errno == EINVAL, "Set with invalid index"); - ok(array_get(&arr, 0) == NULL && errno == EINVAL, "Get with invalid index"); - - for (size_t i = 0; i < len; i++) { - int *v; - ok(array_add(&arr, &values[i]) && array_length(&arr) == i+1, - "Add integer: %zu = %d", i, values[i]); - ok((v = array_get(&arr, i)) && *v == values[i], - "Get integer: %zu = %d", i, *v); - } - - for (size_t i = 0; i < len; i++) { - ok(array_set(&arr, i, &values[len-i-1]) && array_length(&arr) == len, - "Set array element: %zu = %d", i, values[len-i-1]); - } - - for (size_t i = 0; i < len; i++) { - int *v; - ok((v = array_get(&arr, i)) && *v == values[len-i-1], - "Get array element: %zu = %d", i, *v); - } - - array_clear(&arr); - ok(array_length(&arr) == 0 && array_get(&arr, 0) == NULL && errno == EINVAL, "Clear"); - - for (size_t i = 0; i < len; i++) { - ok(array_add(&arr, &values[i]) && array_length(&arr) == i+1, - "Re-add integer: %zu = %d", i, values[i]); - } - - int old, *tmp; - ok((tmp = array_get(&arr, 0)) && (old = *tmp) && array_set(&arr, 0, NULL) && - array_get(&arr, 0) == tmp && *tmp == 0 && array_set(&arr, 0, &old) && - array_get(&arr, 0) == tmp && *tmp == old, "Set array element NULL"); - ok(!array_set(&arr, array_length(&arr), &values[0]) && errno == EINVAL, "Get past end of array"); - ok(!array_get(&arr, array_length(&arr)) && errno == EINVAL, "Get past end of array"); - - ok(!array_remove(&arr, array_length(&arr)) && errno == EINVAL, "Remove past end of array"); - - int *v; - - size_t len_before = array_length(&arr); - ok(array_remove(&arr, 2) && array_length(&arr) == len_before-1 && - (v = array_get(&arr, 0)) && *v == values[0] && - (v = array_get(&arr, 1)) && *v == values[1] && - (v = array_get(&arr, 2)) && *v == values[3] && - (v = array_get(&arr, 3)) && *v == values[4], - "Remove element 2"); - - len_before = array_length(&arr); - ok(array_remove(&arr, 0) && array_length(&arr) == len_before-1 && - (v = array_get(&arr, 0)) && *v == values[1] && - (v = array_get(&arr, 1)) && *v == values[3] && - (v = array_get(&arr, 2)) && *v == values[4], - "Remove first element"); - - len_before = array_length(&arr); - ok(array_remove(&arr, len_before-1) && array_length(&arr) == len_before-1 && - (v = array_get(&arr, 0)) && *v == values[1] && - (v = array_get(&arr, 1)) && *v == values[3], - "Remove last element"); - - array_release(&arr); -} - -static void test_large_objects(void) { - Array arr; - array_init_sized(&arr, sizeof(Item)); - ok(array_length(&arr) == 0 && array_get(&arr, 0) == NULL && errno == EINVAL, - "Initialization"); - - Item items[len]; - - for (size_t i = 0; i < len; i++) { - snprintf(items[i].key, sizeof items[i].key, "key: %zu", i); - items[i].value = values[i]; - Item *item; - ok(array_add(&arr, &items[i]) && array_length(&arr) == i+1, - "Add item: %zu = { '%s' = %d }", i, items[i].key, items[i].value); - ok((item = array_get(&arr, i)) && item != &items[i] && item_compare(item, &items[i]), - "Get item: %zu = { '%s' = %d }", i, item->key, item->value); - } - - for (size_t i = 0; i < len; i++) { - Item *item = &items[len-i-1]; - ok(array_set(&arr, i, item) && array_length(&arr) == len, - "Set array element: %zu = { '%s' = %d }", i, item->key, item->value); - } - - for (size_t i = 0; i < len; i++) { - Item *item; - ok((item = array_get(&arr, i)) && item != &items[len-i-1] && item_compare(item, &items[len-i-1]), - "Get item: %zu = { '%s' = %d }", i, item->key, item->value); - } - - ok(!array_add_ptr(&arr, &items[0]) && errno == ENOTSUP && array_length(&arr) == len, - "Adding pointer to non pointer array"); - ok(!array_set_ptr(&arr, 0, &items[0]) && errno == ENOTSUP && item_compare(array_get(&arr, 0), &items[len-1]), - "Setting pointer in non pointer array"); - - array_clear(&arr); - ok(array_length(&arr) == 0 && array_get(&arr, 0) == NULL && errno == EINVAL, "Clear"); - - array_release(&arr); -} - -static void test_pointers(void) { - - Array arr; - - array_init_sized(&arr, 1); - ok(array_length(&arr) == 0 && array_get_ptr(&arr, 0) == NULL && errno == ENOTSUP, - "Initialization with size 1"); - - ok(!array_add_ptr(&arr, &arr) && errno == ENOTSUP && array_get_ptr(&arr, 0) == NULL, - "Add pointer to non-pointer array"); - - errno = 0; - char byte = '_', *ptr; - ok(array_add(&arr, &byte) && (ptr = array_get(&arr, 0)) && *ptr == byte, - "Add byte element"); - ok(!array_get_ptr(&arr, 0) && errno == ENOTSUP, "Get pointer from non-pointer array"); - - array_init(&arr); - ok(array_length(&arr) == 0 && array_get_ptr(&arr, 0) == NULL && errno == EINVAL, - "Initialization"); - - Item *items[len]; - - for (size_t i = 0; i < len; i++) { - items[i] = malloc(sizeof(Item)); - snprintf(items[i]->key, sizeof(items[i]->key), "key: %zu", i); - items[i]->value = values[i]; - } - - for (size_t i = 0; i < len; i++) { - Item *item; - ok(array_add_ptr(&arr, items[i]) && array_length(&arr) == i+1, - "Add item: %zu = %p", i, (void*)items[i]); - ok((item = array_get_ptr(&arr, i)) && item == items[i], - "Get item: %zu = %p", i, (void*)item); - } - - for (size_t i = 0; i < len; i++) { - Item *item = items[len-i-1]; - ok(array_set_ptr(&arr, i, item) && array_length(&arr) == len, - "Set item: %zu = %p", i, (void*)item); - } - - for (size_t i = 0; i < len; i++) { - Item *item; - ok((item = array_get_ptr(&arr, i)) && item == items[len-i-1], - "Get item: %zu = %p", i, (void*)item); - } - - Item *tmp; - ok((tmp = array_get_ptr(&arr, 0)) && array_set_ptr(&arr, 0, NULL) && - array_get_ptr(&arr, 0) == NULL && array_set_ptr(&arr, 0, tmp) && - array_get_ptr(&arr, 0) == tmp, "Set pointer NULL"); - ok(!array_set_ptr(&arr, array_length(&arr), items[0]) && errno == EINVAL, "Set pointer past end of array"); - ok(!array_get_ptr(&arr, array_length(&arr)) && errno == EINVAL, "Get pointer past end of array"); - - array_clear(&arr); - ok(array_length(&arr) == 0 && array_get_ptr(&arr, 0) == NULL && errno == EINVAL, "Clear"); - - for (size_t i = 0; i < len; i++) { - ok(array_add_ptr(&arr, items[i]) && array_length(&arr) == i+1, - "Re-add item: %zu = %p", i, (void*)items[i]); - } - array_release_full(&arr); -} - -int main(int argc, char *argv[]) { - plan_no_plan(); - - test_small_objects(); - test_large_objects(); - test_pointers(); - - return exit_status(); -} diff --git a/core/buffer-test.c b/core/buffer-test.c new file mode 100644 index 0000000..cb3f1d9 --- /dev/null +++ b/core/buffer-test.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include "tap.h" +#include "buffer.h" + +static bool compare(Buffer *buf, const char *data, size_t len) { + return buf->len == len && (len == 0 || memcmp(buf->data, data, buf->len) == 0); +} + +static bool compare0(Buffer *buf, const char *data) { + return buf->len == strlen(data)+1 && memcmp(buf->data, data, buf->len) == 0; +} + +int main(int argc, char *argv[]) { + Buffer buf; + + plan_no_plan(); + + buffer_init(&buf); + ok(buffer_content(&buf) == NULL && buffer_length(&buf) == 0 && buffer_capacity(&buf) == 0, "Initialization"); + ok(buffer_insert(&buf, 0, "foo", 0) && buffer_content(&buf) == NULL && + buffer_length(&buf) == 0 && buffer_capacity(&buf) == 0, "Insert zero length data"); + ok(!buffer_insert0(&buf, 1, "foo"), "Insert string at invalid position"); + + ok(buffer_insert0(&buf, 0, "") && compare0(&buf, ""), "Insert empty string"); + ok(buffer_insert0(&buf, 0, "foo") && compare0(&buf, "foo"), "Insert string at start"); + ok(buffer_insert0(&buf, 1, "l") && compare0(&buf, "floo"), "Insert string in middle"); + ok(buffer_insert0(&buf, 4, "r") && compare0(&buf, "floor"), "Insert string at end"); + + ok(buffer_put0(&buf, "") && compare0(&buf, ""), "Put empty string"); + ok(buffer_put0(&buf, "bar") && compare0(&buf, "bar"), "Put string"); + + ok(buffer_prepend0(&buf, "foo") && compare0(&buf, "foobar"), "Prepend string"); + ok(buffer_append0(&buf, "baz") && compare0(&buf, "foobarbaz"), "Append string"); + + buffer_release(&buf); + ok(buf.data == NULL && buffer_length(&buf) == 0 && buffer_capacity(&buf) == 0, "Release"); + + ok(buffer_insert(&buf, 0, "foo", 0) && compare(&buf, "", 0), "Insert zero length data"); + ok(buffer_insert(&buf, 0, "foo", 3) && compare(&buf, "foo", 3), "Insert data at start"); + ok(buffer_insert(&buf, 1, "l", 1) && compare(&buf, "floo", 4), "Insert data in middle"); + ok(buffer_insert(&buf, 4, "r", 1) && compare(&buf, "floor", 5), "Insert data at end"); + + size_t cap = buffer_capacity(&buf); + buffer_clear(&buf); + ok(buf.data && buffer_length(&buf) == 0 && buffer_capacity(&buf) == cap, "Clear"); + + ok(buffer_put(&buf, "foo", 0) && compare(&buf, "", 0), "Put zero length data"); + ok(buffer_put(&buf, "bar", 3) && compare(&buf, "bar", 3), "Put data"); + + ok(buffer_prepend(&buf, "foo\0", 4) && compare(&buf, "foo\0bar", 7), "Prepend data"); + ok(buffer_append(&buf, "\0baz", 4) && compare(&buf, "foo\0bar\0baz", 11), "Append data"); + + ok(buffer_grow(&buf, cap+1) && compare(&buf, "foo\0bar\0baz", 11) && buffer_capacity(&buf) >= cap+1, "Grow"); + + const char *content = buffer_content(&buf); + char *data = buffer_move(&buf); + ok(data == content && buffer_length(&buf) == 0 && buffer_capacity(&buf) == 0 && buffer_content(&buf) == NULL, "Move"); + ok(buffer_append0(&buf, "foo") && buffer_content(&buf) != data, "Modify after move"); + free(data); + + skip_if(TIS_INTERPRETER, 1, "vsnprintf not supported") { + + ok(buffer_printf(&buf, "Test: %d\n", 42) && compare0(&buf, "Test: 42\n"), "Set formatted"); + ok(buffer_printf(&buf, "%d\n", 42) && compare0(&buf, "42\n"), "Set formatted overwrite"); + buffer_clear(&buf); + + ok(buffer_printf(&buf, "") && compare0(&buf, ""), "Set formatted empty string"); + buffer_clear(&buf); + + bool append = true; + for (int i = 1; i <= 10; i++) + append &= buffer_appendf(&buf, "%d", i); + ok(append && compare0(&buf, "12345678910"), "Append formatted"); + buffer_clear(&buf); + + append = true; + for (int i = 1; i <= 10; i++) + append &= buffer_appendf(&buf, ""); + ok(append && compare0(&buf, ""), "Append formatted empty string"); + buffer_clear(&buf); + } + + buffer_release(&buf); + + return exit_status(); +} diff --git a/core/buffer.c b/core/buffer.c deleted file mode 100644 index cb3f1d9..0000000 --- a/core/buffer.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include -#include -#include -#include "tap.h" -#include "buffer.h" - -static bool compare(Buffer *buf, const char *data, size_t len) { - return buf->len == len && (len == 0 || memcmp(buf->data, data, buf->len) == 0); -} - -static bool compare0(Buffer *buf, const char *data) { - return buf->len == strlen(data)+1 && memcmp(buf->data, data, buf->len) == 0; -} - -int main(int argc, char *argv[]) { - Buffer buf; - - plan_no_plan(); - - buffer_init(&buf); - ok(buffer_content(&buf) == NULL && buffer_length(&buf) == 0 && buffer_capacity(&buf) == 0, "Initialization"); - ok(buffer_insert(&buf, 0, "foo", 0) && buffer_content(&buf) == NULL && - buffer_length(&buf) == 0 && buffer_capacity(&buf) == 0, "Insert zero length data"); - ok(!buffer_insert0(&buf, 1, "foo"), "Insert string at invalid position"); - - ok(buffer_insert0(&buf, 0, "") && compare0(&buf, ""), "Insert empty string"); - ok(buffer_insert0(&buf, 0, "foo") && compare0(&buf, "foo"), "Insert string at start"); - ok(buffer_insert0(&buf, 1, "l") && compare0(&buf, "floo"), "Insert string in middle"); - ok(buffer_insert0(&buf, 4, "r") && compare0(&buf, "floor"), "Insert string at end"); - - ok(buffer_put0(&buf, "") && compare0(&buf, ""), "Put empty string"); - ok(buffer_put0(&buf, "bar") && compare0(&buf, "bar"), "Put string"); - - ok(buffer_prepend0(&buf, "foo") && compare0(&buf, "foobar"), "Prepend string"); - ok(buffer_append0(&buf, "baz") && compare0(&buf, "foobarbaz"), "Append string"); - - buffer_release(&buf); - ok(buf.data == NULL && buffer_length(&buf) == 0 && buffer_capacity(&buf) == 0, "Release"); - - ok(buffer_insert(&buf, 0, "foo", 0) && compare(&buf, "", 0), "Insert zero length data"); - ok(buffer_insert(&buf, 0, "foo", 3) && compare(&buf, "foo", 3), "Insert data at start"); - ok(buffer_insert(&buf, 1, "l", 1) && compare(&buf, "floo", 4), "Insert data in middle"); - ok(buffer_insert(&buf, 4, "r", 1) && compare(&buf, "floor", 5), "Insert data at end"); - - size_t cap = buffer_capacity(&buf); - buffer_clear(&buf); - ok(buf.data && buffer_length(&buf) == 0 && buffer_capacity(&buf) == cap, "Clear"); - - ok(buffer_put(&buf, "foo", 0) && compare(&buf, "", 0), "Put zero length data"); - ok(buffer_put(&buf, "bar", 3) && compare(&buf, "bar", 3), "Put data"); - - ok(buffer_prepend(&buf, "foo\0", 4) && compare(&buf, "foo\0bar", 7), "Prepend data"); - ok(buffer_append(&buf, "\0baz", 4) && compare(&buf, "foo\0bar\0baz", 11), "Append data"); - - ok(buffer_grow(&buf, cap+1) && compare(&buf, "foo\0bar\0baz", 11) && buffer_capacity(&buf) >= cap+1, "Grow"); - - const char *content = buffer_content(&buf); - char *data = buffer_move(&buf); - ok(data == content && buffer_length(&buf) == 0 && buffer_capacity(&buf) == 0 && buffer_content(&buf) == NULL, "Move"); - ok(buffer_append0(&buf, "foo") && buffer_content(&buf) != data, "Modify after move"); - free(data); - - skip_if(TIS_INTERPRETER, 1, "vsnprintf not supported") { - - ok(buffer_printf(&buf, "Test: %d\n", 42) && compare0(&buf, "Test: 42\n"), "Set formatted"); - ok(buffer_printf(&buf, "%d\n", 42) && compare0(&buf, "42\n"), "Set formatted overwrite"); - buffer_clear(&buf); - - ok(buffer_printf(&buf, "") && compare0(&buf, ""), "Set formatted empty string"); - buffer_clear(&buf); - - bool append = true; - for (int i = 1; i <= 10; i++) - append &= buffer_appendf(&buf, "%d", i); - ok(append && compare0(&buf, "12345678910"), "Append formatted"); - buffer_clear(&buf); - - append = true; - for (int i = 1; i <= 10; i++) - append &= buffer_appendf(&buf, ""); - ok(append && compare0(&buf, ""), "Append formatted empty string"); - buffer_clear(&buf); - } - - buffer_release(&buf); - - return exit_status(); -} diff --git a/core/map-test.c b/core/map-test.c new file mode 100644 index 0000000..7a23d57 --- /dev/null +++ b/core/map-test.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include "tap.h" +#include "map.h" + +static bool get(Map *map, const char *key, const void *data) { + return map_get(map, key) == data && map_closest(map, key) == data; +} + +static bool compare(const char *key, void *value, void *data) { + Map *map = data; + ok(map_get(map, key) == value, "Compare map content"); + return true; +} + +static bool once(const char *key, void *value, void *data) { + int *counter = data; + (*counter)++; + return false; +} + +static bool visit(const char *key, void *value, void *data) { + int *index = value; + int *visited = data; + visited[*index]++; + return true; +} + +static int order_counter; + +static bool order(const char *key, void *value, void *data) { + int *index = value; + int *order = data; + order[*index] = ++order_counter; + return true; +} + +int main(int argc, char *argv[]) { + const char *key = "404"; + const int values[3] = { 0, 1, 2 }; + + plan_no_plan(); + + Map *map = map_new(); + + ok(map && map_empty(map), "Creation"); + ok(map_first(map, &key) == NULL && strcmp(key, "404") == 0, "First on empty map"); + ok(map_empty(map_prefix(map, "404")), "Empty prefix map"); + + ok(!map_get(map, "404"), "Get non-existing key"); + ok(!map_contains(map, "404"), "Contains non-existing key"); + ok(!map_closest(map, "404") && errno == ENOENT, "Closest non-existing key"); + + ok(!map_put(map, "a", NULL) && errno == EINVAL && map_empty(map) && !map_get(map, "a"), "Put NULL value"); + ok(map_put(map, "a", &values[0]) && !map_empty(map) && get(map, "a", &values[0]), "Put 1"); + ok(map_first(map, &key) == &values[0] && strcmp(key, "a") == 0, "First on map with 1 value"); + key = NULL; + ok(map_first(map_prefix(map, "a"), &key) == &values[0] && strcmp(key, "a") == 0, "First on prefix map"); + ok(map_contains(map, "a"), "Contains existing key"); + ok(map_closest(map, "a") == &values[0], "Closest match existing key"); + ok(!map_put(map, "a", &values[1]) && errno == EEXIST && get(map, "a", &values[0]), "Put duplicate"); + ok(map_put(map, "cafebabe", &values[2]) && get(map, "cafebabe", &values[2]), "Put 2"); + ok(map_put(map, "cafe", &values[1]) && get(map, "cafe", &values[1]), "Put 3"); + key = NULL; + ok(map_first(map_prefix(map, "cafe"), &key) == &values[1] && strcmp(key, "cafe") == 0, "First on prefix map with multiple suffixes"); + + Map *copy = map_new(); + ok(map_copy(copy, map), "Copy"); + ok(!map_empty(copy), "Not empty after copying"); + map_iterate(copy, compare, map); + map_iterate(map, compare, copy); + + int counter = 0; + map_iterate(copy, once, &counter); + ok(counter == 1, "Iterate stop condition"); + + ok(!map_get(map, "ca") && !map_closest(map, "ca") && errno == 0, "Closest ambigious"); + + int visited[] = { 0, 0, 0 }; + + map_iterate(map, visit, &visited); + ok(visited[0] == 1 && visited[1] == 1 && visited[2] == 1, "Iterate map"); + + memset(visited, 0, sizeof visited); + order_counter = 0; + map_iterate(map, order, &visited); + ok(visited[0] == 1 && visited[1] == 2 && visited[2] == 3, "Ordered iteration"); + + memset(visited, 0, sizeof visited); + map_iterate(map_prefix(map, "ca"), visit, &visited); + ok(visited[0] == 0 && visited[1] == 1 && visited[2] == 1, "Iterate sub map"); + + memset(visited, 0, sizeof visited); + order_counter = 0; + map_iterate(map_prefix(map, "ca"), order, &visited); + ok(visited[0] == 0 && visited[1] == 1 && visited[2] == 2, "Ordered sub map iteration"); + + ok(map_empty(map_prefix(map, "404")), "Empty map for non-existing prefix"); + + ok(!map_delete(map, "404"), "Delete non-existing key"); + ok(map_delete(map, "cafe") == &values[1] && !map_get(map, "cafe"), "Delete existing key"); + ok(map_closest(map, "cafe") == &values[2], "Closest unambigious"); + ok(map_put(map, "cafe", &values[1]) && get(map, "cafe", &values[1]), "Put 3 again"); + + map_clear(map); + ok(map_empty(map), "Empty after clean"); + + map_free(map); + map_free(copy); + + return exit_status(); +} diff --git a/core/map.c b/core/map.c deleted file mode 100644 index 7a23d57..0000000 --- a/core/map.c +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include -#include -#include -#include -#include "tap.h" -#include "map.h" - -static bool get(Map *map, const char *key, const void *data) { - return map_get(map, key) == data && map_closest(map, key) == data; -} - -static bool compare(const char *key, void *value, void *data) { - Map *map = data; - ok(map_get(map, key) == value, "Compare map content"); - return true; -} - -static bool once(const char *key, void *value, void *data) { - int *counter = data; - (*counter)++; - return false; -} - -static bool visit(const char *key, void *value, void *data) { - int *index = value; - int *visited = data; - visited[*index]++; - return true; -} - -static int order_counter; - -static bool order(const char *key, void *value, void *data) { - int *index = value; - int *order = data; - order[*index] = ++order_counter; - return true; -} - -int main(int argc, char *argv[]) { - const char *key = "404"; - const int values[3] = { 0, 1, 2 }; - - plan_no_plan(); - - Map *map = map_new(); - - ok(map && map_empty(map), "Creation"); - ok(map_first(map, &key) == NULL && strcmp(key, "404") == 0, "First on empty map"); - ok(map_empty(map_prefix(map, "404")), "Empty prefix map"); - - ok(!map_get(map, "404"), "Get non-existing key"); - ok(!map_contains(map, "404"), "Contains non-existing key"); - ok(!map_closest(map, "404") && errno == ENOENT, "Closest non-existing key"); - - ok(!map_put(map, "a", NULL) && errno == EINVAL && map_empty(map) && !map_get(map, "a"), "Put NULL value"); - ok(map_put(map, "a", &values[0]) && !map_empty(map) && get(map, "a", &values[0]), "Put 1"); - ok(map_first(map, &key) == &values[0] && strcmp(key, "a") == 0, "First on map with 1 value"); - key = NULL; - ok(map_first(map_prefix(map, "a"), &key) == &values[0] && strcmp(key, "a") == 0, "First on prefix map"); - ok(map_contains(map, "a"), "Contains existing key"); - ok(map_closest(map, "a") == &values[0], "Closest match existing key"); - ok(!map_put(map, "a", &values[1]) && errno == EEXIST && get(map, "a", &values[0]), "Put duplicate"); - ok(map_put(map, "cafebabe", &values[2]) && get(map, "cafebabe", &values[2]), "Put 2"); - ok(map_put(map, "cafe", &values[1]) && get(map, "cafe", &values[1]), "Put 3"); - key = NULL; - ok(map_first(map_prefix(map, "cafe"), &key) == &values[1] && strcmp(key, "cafe") == 0, "First on prefix map with multiple suffixes"); - - Map *copy = map_new(); - ok(map_copy(copy, map), "Copy"); - ok(!map_empty(copy), "Not empty after copying"); - map_iterate(copy, compare, map); - map_iterate(map, compare, copy); - - int counter = 0; - map_iterate(copy, once, &counter); - ok(counter == 1, "Iterate stop condition"); - - ok(!map_get(map, "ca") && !map_closest(map, "ca") && errno == 0, "Closest ambigious"); - - int visited[] = { 0, 0, 0 }; - - map_iterate(map, visit, &visited); - ok(visited[0] == 1 && visited[1] == 1 && visited[2] == 1, "Iterate map"); - - memset(visited, 0, sizeof visited); - order_counter = 0; - map_iterate(map, order, &visited); - ok(visited[0] == 1 && visited[1] == 2 && visited[2] == 3, "Ordered iteration"); - - memset(visited, 0, sizeof visited); - map_iterate(map_prefix(map, "ca"), visit, &visited); - ok(visited[0] == 0 && visited[1] == 1 && visited[2] == 1, "Iterate sub map"); - - memset(visited, 0, sizeof visited); - order_counter = 0; - map_iterate(map_prefix(map, "ca"), order, &visited); - ok(visited[0] == 0 && visited[1] == 1 && visited[2] == 2, "Ordered sub map iteration"); - - ok(map_empty(map_prefix(map, "404")), "Empty map for non-existing prefix"); - - ok(!map_delete(map, "404"), "Delete non-existing key"); - ok(map_delete(map, "cafe") == &values[1] && !map_get(map, "cafe"), "Delete existing key"); - ok(map_closest(map, "cafe") == &values[2], "Closest unambigious"); - ok(map_put(map, "cafe", &values[1]) && get(map, "cafe", &values[1]), "Put 3 again"); - - map_clear(map); - ok(map_empty(map), "Empty after clean"); - - map_free(map); - map_free(copy); - - return exit_status(); -} diff --git a/core/text-test.c b/core/text-test.c new file mode 100644 index 0000000..5a8c001 --- /dev/null +++ b/core/text-test.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include +#include +#include "tap.h" +#include "text.h" +#include "text-util.h" +#include "util.h" + +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif + +static bool insert(Text *txt, size_t pos, const char *data) { + return text_insert(txt, pos, data, strlen(data)); +} + +static bool isempty(Text *txt) { + return text_size(txt) == 0; +} + +static bool compare_iterator_forward(Iterator *it, const char *data) { + char buf[BUFSIZ] = "", b; + while (text_iterator_byte_get(it, &b)) { + buf[it->pos] = b; + text_iterator_byte_next(it, NULL); + } + return strcmp(data, buf) == 0; +} + +static bool compare_iterator_backward(Iterator *it, const char *data) { + char buf[BUFSIZ] = "", b; + while (text_iterator_byte_get(it, &b)) { + buf[it->pos] = b; + text_iterator_byte_prev(it, NULL); + } + return strcmp(data, buf) == 0; +} + +static bool compare_iterator_both(Text *txt, const char *data) { + Iterator it = text_iterator_get(txt, 0); + bool forward = compare_iterator_forward(&it, data); + text_iterator_byte_prev(&it, NULL); + bool forward_backward = compare_iterator_backward(&it, data); + it = text_iterator_get(txt, text_size(txt)); + bool backward = compare_iterator_backward(&it, data); + text_iterator_byte_next(&it, NULL); + bool backward_forward = compare_iterator_forward(&it, data); + return forward && backward && forward_backward && backward_forward; +} + +static bool compare(Text *txt, const char *data) { + char buf[BUFSIZ]; + size_t len = text_bytes_get(txt, 0, sizeof(buf)-1, buf); + buf[len] = '\0'; + return len == strlen(data) && strcmp(buf, data) == 0 && + compare_iterator_both(txt, data); +} + +int main(int argc, char *argv[]) { + Text *txt; + + plan_no_plan(); + + skip_if(TIS_INTERPRETER, 2, "I/O related") { + txt = text_load("/"); + ok(txt == NULL && errno == EISDIR, "Opening directory"); + + if (access("/etc/shadow", F_OK) == 0) { + txt = text_load("/etc/shadow"); + ok(txt == NULL && errno == EACCES, "Opening file without sufficient permissions"); + } + } + + txt = text_load(NULL); + ok(txt != NULL && isempty(txt), "Opening empty file"); + + Iterator it = text_iterator_get(txt, 0); + ok(text_iterator_valid(&it) && it.pos == 0, "Iterator on empty file"); + char b = '_'; + ok(text_iterator_byte_get(&it, &b) && b == '\0', "Read EOF from iterator of empty file"); + b = '_'; + ok(!text_iterator_byte_prev(&it, &b) && b == '_' && + !text_iterator_valid(&it), "Moving iterator beyond start of file"); + ok(!text_iterator_byte_get(&it, &b) && b == '_' && + !text_iterator_valid(&it), "Access iterator beyond start of file"); + ok(text_iterator_byte_next(&it, &b) && b == '\0' && + text_iterator_valid(&it), "Moving iterator back from beyond start of file"); + b = '_'; + ok(text_iterator_byte_get(&it, &b) && b == '\0' && + text_iterator_valid(&it), "Accessing iterator after moving back from beyond start of file"); + b = '_'; + ok(!text_iterator_byte_next(&it, &b) && b == '_' && + !text_iterator_valid(&it), "Moving iterator beyond end of file"); + ok(!text_iterator_byte_get(&it, &b) && b == '_' && + !text_iterator_valid(&it), "Accessing iterator beyond end of file"); + ok(text_iterator_byte_prev(&it, &b) && b == '\0' && + text_iterator_valid(&it), "Moving iterator back from beyond end of file"); + b = '_'; + ok(text_iterator_byte_get(&it, &b) && b == '\0' && + text_iterator_valid(&it), "Accessing iterator after moving back from beyond start of file"); + + ok(insert(txt, 1, "") && isempty(txt), "Inserting empty data"); + ok(!insert(txt, 1, " ") && isempty(txt), "Inserting with invalid offset"); + + /* test cached insertion (i.e. in-place with only one piece) */ + ok(insert(txt, 0, "3") && compare(txt, "3"), "Inserting into empty document (cached)"); + ok(insert(txt, 0, "1") && compare(txt, "13"), "Inserting at begin (cached)"); + ok(insert(txt, 1, "2") && compare(txt, "123"), "Inserting in middle (cached)"); + ok(insert(txt, text_size(txt), "4") && compare(txt, "1234"), "Inserting at end (cached)"); + + ok(text_delete(txt, text_size(txt), 0) && compare(txt, "1234"), "Deleting empty range"); + ok(!text_delete(txt, text_size(txt), 1) && compare(txt, "1234"), "Deleting invalid offset"); + ok(!text_delete(txt, 0, text_size(txt)+5) && compare(txt, "1234"), "Deleting invalid range"); + + ok(text_undo(txt) == 0 && compare(txt, ""), "Reverting to empty document"); + ok(text_redo(txt) != EPOS /* == text_size(txt) */ && compare(txt, "1234"), "Restoring previsous content"); + + /* test cached deletion (i.e. in-place with only one piece) */ + ok(text_delete(txt, text_size(txt)-1, 1) && compare(txt, "123"), "Deleting at end (cached)"); + ok(text_delete(txt, 1, 1) && compare(txt, "13"), "Deleting in middle (cached)"); + ok(text_delete(txt, 0, 1) && compare(txt, "3"), "Deleting at begin (cached)"); + ok(text_delete(txt, 0, 1) && compare(txt, ""), "Deleting to empty document (cached)"); + + /* test regular insertion (i.e. with multiple pieces) */ + text_snapshot(txt); + ok(insert(txt, 0, "3") && compare(txt, "3"), "Inserting into empty document"); + text_snapshot(txt); + ok(insert(txt, 0, "1") && compare(txt, "13"), "Inserting at begin"); + text_snapshot(txt); + ok(insert(txt, 1, "2") && compare(txt, "123"), "Inserting in between"); + text_snapshot(txt); + ok(insert(txt, text_size(txt), "46") && compare(txt, "12346"), "Inserting at end"); + text_snapshot(txt); + ok(insert(txt, 4, "5") && compare(txt, "123456"), "Inserting in middle"); + text_snapshot(txt); + ok(insert(txt, text_size(txt), "789") && compare(txt, "123456789"), "Inserting at end"); + text_snapshot(txt); + ok(insert(txt, text_size(txt), "0") && compare(txt, "1234567890"), "Inserting at end"); + + /* test simple undo / redo oparations */ + ok(text_undo(txt) != EPOS && compare(txt, "123456789"), "Undo 1"); + ok(text_undo(txt) != EPOS && compare(txt, "123456"), "Undo 2"); + ok(text_undo(txt) != EPOS && compare(txt, "12346"), "Undo 3"); + ok(text_undo(txt) != EPOS && compare(txt, "123"), "Undo 3"); + ok(text_undo(txt) != EPOS && compare(txt, "13"), "Undo 5"); + ok(text_undo(txt) != EPOS && compare(txt, "3"), "Undo 6"); + ok(text_undo(txt) != EPOS && compare(txt, ""), "Undo 6"); + ok(text_redo(txt) != EPOS && compare(txt, "3"), "Redo 1"); + ok(text_redo(txt) != EPOS && compare(txt, "13"), "Redo 2"); + ok(text_redo(txt) != EPOS && compare(txt, "123"), "Redo 3"); + ok(text_redo(txt) != EPOS && compare(txt, "12346"), "Redo 4"); + ok(text_redo(txt) != EPOS && compare(txt, "123456"), "Redo 5"); + ok(text_redo(txt) != EPOS && compare(txt, "123456789"), "Redo 6"); + ok(text_redo(txt) != EPOS && compare(txt, "1234567890"), "Redo 7"); + + /* test regular deletion (i.e. with multiple pieces) */ + ok(text_delete(txt, 8, 2) && compare(txt, "12345678"), "Deleting midway start"); + text_undo(txt); + ok(text_delete(txt, 2, 6) && compare(txt, "1290"), "Deleting midway end"); + text_undo(txt); + ok(text_delete(txt, 7, 1) && compare(txt, "123456790"), "Deleting midway both same piece"); + text_undo(txt); + ok(text_delete(txt, 0, 5) && compare(txt, "67890"), "Deleting at begin"); + text_undo(txt); + ok(text_delete(txt, 5, 5) && compare(txt, "12345"), "Deleting at end"); + + ok(text_mark_get(txt, text_mark_set(txt, -1)) == EPOS, "Mark invalid 1"); + ok(text_mark_get(txt, text_mark_set(txt, text_size(txt)+1)) == EPOS, "Mark invalid 2"); + + const char *chunk = "new content"; + const size_t delta = strlen(chunk); + size_t positions[] = { 0, 1, text_size(txt)/2, text_size(txt)-1 }; + text_snapshot(txt); + for (size_t i = 0; i < LENGTH(positions); i++) { + size_t pos = positions[i]; + size_t newpos = pos+delta; + Mark bof = text_mark_set(txt, 0); + ok(text_mark_get(txt, bof) == 0, "Mark at beginning of file"); + Mark mof = text_mark_set(txt, pos); + ok(text_mark_get(txt, mof) == pos, "Mark in the middle"); + Mark eof = text_mark_set(txt, text_size(txt)); + ok(text_mark_get(txt, eof) == text_size(txt), "Mark at end of file"); + ok(insert(txt, pos, chunk), "Insert before mark"); + ok(text_mark_get(txt, bof) == ((pos == 0) ? delta : 0), "Mark at beginning adjusted 1"); + ok(text_mark_get(txt, mof) == pos+delta, "Mark in the middle adjusted 1"); + ok(text_mark_get(txt, eof) == text_size(txt), "Mark at end adjusted 1"); + ok(insert(txt, pos+delta+1, chunk), "Insert after mark"); + ok(text_mark_get(txt, bof) == ((pos == 0) ? delta : 0), "Mark at beginning adjusted 2"); + ok(text_mark_get(txt, mof) == pos+delta, "Mark in the middle adjusted 2"); + ok(text_mark_get(txt, eof) == text_size(txt), "Mark at end adjusted 2"); + text_snapshot(txt); + ok(text_delete(txt, pos+delta, 1), "Deleting mark"); + ok(text_mark_get(txt, mof) == EPOS, "Mark in the middle deleted"); + text_undo(txt); + ok(text_mark_get(txt, mof) == pos+delta, "Mark restored"); + text_undo(txt); + } + text_free(txt); + + return exit_status(); +} diff --git a/core/text.c b/core/text.c deleted file mode 100644 index 5a8c001..0000000 --- a/core/text.c +++ /dev/null @@ -1,204 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "tap.h" -#include "text.h" -#include "text-util.h" -#include "util.h" - -#ifndef BUFSIZ -#define BUFSIZ 1024 -#endif - -static bool insert(Text *txt, size_t pos, const char *data) { - return text_insert(txt, pos, data, strlen(data)); -} - -static bool isempty(Text *txt) { - return text_size(txt) == 0; -} - -static bool compare_iterator_forward(Iterator *it, const char *data) { - char buf[BUFSIZ] = "", b; - while (text_iterator_byte_get(it, &b)) { - buf[it->pos] = b; - text_iterator_byte_next(it, NULL); - } - return strcmp(data, buf) == 0; -} - -static bool compare_iterator_backward(Iterator *it, const char *data) { - char buf[BUFSIZ] = "", b; - while (text_iterator_byte_get(it, &b)) { - buf[it->pos] = b; - text_iterator_byte_prev(it, NULL); - } - return strcmp(data, buf) == 0; -} - -static bool compare_iterator_both(Text *txt, const char *data) { - Iterator it = text_iterator_get(txt, 0); - bool forward = compare_iterator_forward(&it, data); - text_iterator_byte_prev(&it, NULL); - bool forward_backward = compare_iterator_backward(&it, data); - it = text_iterator_get(txt, text_size(txt)); - bool backward = compare_iterator_backward(&it, data); - text_iterator_byte_next(&it, NULL); - bool backward_forward = compare_iterator_forward(&it, data); - return forward && backward && forward_backward && backward_forward; -} - -static bool compare(Text *txt, const char *data) { - char buf[BUFSIZ]; - size_t len = text_bytes_get(txt, 0, sizeof(buf)-1, buf); - buf[len] = '\0'; - return len == strlen(data) && strcmp(buf, data) == 0 && - compare_iterator_both(txt, data); -} - -int main(int argc, char *argv[]) { - Text *txt; - - plan_no_plan(); - - skip_if(TIS_INTERPRETER, 2, "I/O related") { - txt = text_load("/"); - ok(txt == NULL && errno == EISDIR, "Opening directory"); - - if (access("/etc/shadow", F_OK) == 0) { - txt = text_load("/etc/shadow"); - ok(txt == NULL && errno == EACCES, "Opening file without sufficient permissions"); - } - } - - txt = text_load(NULL); - ok(txt != NULL && isempty(txt), "Opening empty file"); - - Iterator it = text_iterator_get(txt, 0); - ok(text_iterator_valid(&it) && it.pos == 0, "Iterator on empty file"); - char b = '_'; - ok(text_iterator_byte_get(&it, &b) && b == '\0', "Read EOF from iterator of empty file"); - b = '_'; - ok(!text_iterator_byte_prev(&it, &b) && b == '_' && - !text_iterator_valid(&it), "Moving iterator beyond start of file"); - ok(!text_iterator_byte_get(&it, &b) && b == '_' && - !text_iterator_valid(&it), "Access iterator beyond start of file"); - ok(text_iterator_byte_next(&it, &b) && b == '\0' && - text_iterator_valid(&it), "Moving iterator back from beyond start of file"); - b = '_'; - ok(text_iterator_byte_get(&it, &b) && b == '\0' && - text_iterator_valid(&it), "Accessing iterator after moving back from beyond start of file"); - b = '_'; - ok(!text_iterator_byte_next(&it, &b) && b == '_' && - !text_iterator_valid(&it), "Moving iterator beyond end of file"); - ok(!text_iterator_byte_get(&it, &b) && b == '_' && - !text_iterator_valid(&it), "Accessing iterator beyond end of file"); - ok(text_iterator_byte_prev(&it, &b) && b == '\0' && - text_iterator_valid(&it), "Moving iterator back from beyond end of file"); - b = '_'; - ok(text_iterator_byte_get(&it, &b) && b == '\0' && - text_iterator_valid(&it), "Accessing iterator after moving back from beyond start of file"); - - ok(insert(txt, 1, "") && isempty(txt), "Inserting empty data"); - ok(!insert(txt, 1, " ") && isempty(txt), "Inserting with invalid offset"); - - /* test cached insertion (i.e. in-place with only one piece) */ - ok(insert(txt, 0, "3") && compare(txt, "3"), "Inserting into empty document (cached)"); - ok(insert(txt, 0, "1") && compare(txt, "13"), "Inserting at begin (cached)"); - ok(insert(txt, 1, "2") && compare(txt, "123"), "Inserting in middle (cached)"); - ok(insert(txt, text_size(txt), "4") && compare(txt, "1234"), "Inserting at end (cached)"); - - ok(text_delete(txt, text_size(txt), 0) && compare(txt, "1234"), "Deleting empty range"); - ok(!text_delete(txt, text_size(txt), 1) && compare(txt, "1234"), "Deleting invalid offset"); - ok(!text_delete(txt, 0, text_size(txt)+5) && compare(txt, "1234"), "Deleting invalid range"); - - ok(text_undo(txt) == 0 && compare(txt, ""), "Reverting to empty document"); - ok(text_redo(txt) != EPOS /* == text_size(txt) */ && compare(txt, "1234"), "Restoring previsous content"); - - /* test cached deletion (i.e. in-place with only one piece) */ - ok(text_delete(txt, text_size(txt)-1, 1) && compare(txt, "123"), "Deleting at end (cached)"); - ok(text_delete(txt, 1, 1) && compare(txt, "13"), "Deleting in middle (cached)"); - ok(text_delete(txt, 0, 1) && compare(txt, "3"), "Deleting at begin (cached)"); - ok(text_delete(txt, 0, 1) && compare(txt, ""), "Deleting to empty document (cached)"); - - /* test regular insertion (i.e. with multiple pieces) */ - text_snapshot(txt); - ok(insert(txt, 0, "3") && compare(txt, "3"), "Inserting into empty document"); - text_snapshot(txt); - ok(insert(txt, 0, "1") && compare(txt, "13"), "Inserting at begin"); - text_snapshot(txt); - ok(insert(txt, 1, "2") && compare(txt, "123"), "Inserting in between"); - text_snapshot(txt); - ok(insert(txt, text_size(txt), "46") && compare(txt, "12346"), "Inserting at end"); - text_snapshot(txt); - ok(insert(txt, 4, "5") && compare(txt, "123456"), "Inserting in middle"); - text_snapshot(txt); - ok(insert(txt, text_size(txt), "789") && compare(txt, "123456789"), "Inserting at end"); - text_snapshot(txt); - ok(insert(txt, text_size(txt), "0") && compare(txt, "1234567890"), "Inserting at end"); - - /* test simple undo / redo oparations */ - ok(text_undo(txt) != EPOS && compare(txt, "123456789"), "Undo 1"); - ok(text_undo(txt) != EPOS && compare(txt, "123456"), "Undo 2"); - ok(text_undo(txt) != EPOS && compare(txt, "12346"), "Undo 3"); - ok(text_undo(txt) != EPOS && compare(txt, "123"), "Undo 3"); - ok(text_undo(txt) != EPOS && compare(txt, "13"), "Undo 5"); - ok(text_undo(txt) != EPOS && compare(txt, "3"), "Undo 6"); - ok(text_undo(txt) != EPOS && compare(txt, ""), "Undo 6"); - ok(text_redo(txt) != EPOS && compare(txt, "3"), "Redo 1"); - ok(text_redo(txt) != EPOS && compare(txt, "13"), "Redo 2"); - ok(text_redo(txt) != EPOS && compare(txt, "123"), "Redo 3"); - ok(text_redo(txt) != EPOS && compare(txt, "12346"), "Redo 4"); - ok(text_redo(txt) != EPOS && compare(txt, "123456"), "Redo 5"); - ok(text_redo(txt) != EPOS && compare(txt, "123456789"), "Redo 6"); - ok(text_redo(txt) != EPOS && compare(txt, "1234567890"), "Redo 7"); - - /* test regular deletion (i.e. with multiple pieces) */ - ok(text_delete(txt, 8, 2) && compare(txt, "12345678"), "Deleting midway start"); - text_undo(txt); - ok(text_delete(txt, 2, 6) && compare(txt, "1290"), "Deleting midway end"); - text_undo(txt); - ok(text_delete(txt, 7, 1) && compare(txt, "123456790"), "Deleting midway both same piece"); - text_undo(txt); - ok(text_delete(txt, 0, 5) && compare(txt, "67890"), "Deleting at begin"); - text_undo(txt); - ok(text_delete(txt, 5, 5) && compare(txt, "12345"), "Deleting at end"); - - ok(text_mark_get(txt, text_mark_set(txt, -1)) == EPOS, "Mark invalid 1"); - ok(text_mark_get(txt, text_mark_set(txt, text_size(txt)+1)) == EPOS, "Mark invalid 2"); - - const char *chunk = "new content"; - const size_t delta = strlen(chunk); - size_t positions[] = { 0, 1, text_size(txt)/2, text_size(txt)-1 }; - text_snapshot(txt); - for (size_t i = 0; i < LENGTH(positions); i++) { - size_t pos = positions[i]; - size_t newpos = pos+delta; - Mark bof = text_mark_set(txt, 0); - ok(text_mark_get(txt, bof) == 0, "Mark at beginning of file"); - Mark mof = text_mark_set(txt, pos); - ok(text_mark_get(txt, mof) == pos, "Mark in the middle"); - Mark eof = text_mark_set(txt, text_size(txt)); - ok(text_mark_get(txt, eof) == text_size(txt), "Mark at end of file"); - ok(insert(txt, pos, chunk), "Insert before mark"); - ok(text_mark_get(txt, bof) == ((pos == 0) ? delta : 0), "Mark at beginning adjusted 1"); - ok(text_mark_get(txt, mof) == pos+delta, "Mark in the middle adjusted 1"); - ok(text_mark_get(txt, eof) == text_size(txt), "Mark at end adjusted 1"); - ok(insert(txt, pos+delta+1, chunk), "Insert after mark"); - ok(text_mark_get(txt, bof) == ((pos == 0) ? delta : 0), "Mark at beginning adjusted 2"); - ok(text_mark_get(txt, mof) == pos+delta, "Mark in the middle adjusted 2"); - ok(text_mark_get(txt, eof) == text_size(txt), "Mark at end adjusted 2"); - text_snapshot(txt); - ok(text_delete(txt, pos+delta, 1), "Deleting mark"); - ok(text_mark_get(txt, mof) == EPOS, "Mark in the middle deleted"); - text_undo(txt); - ok(text_mark_get(txt, mof) == pos+delta, "Mark restored"); - text_undo(txt); - } - text_free(txt); - - return exit_status(); -} -- cgit v1.2.3