3e2e697504
with UTF-8 string view (`AMbyteSpan`) values except with the `AMresult::Error` variant. Added `AMstr()` for creating an `AMbyteSpan` from a C string.
229 lines
9.2 KiB
C
229 lines
9.2 KiB
C
#include <setjmp.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* third-party */
|
|
#include <cmocka.h>
|
|
|
|
/* local */
|
|
#include <automerge-c/automerge.h>
|
|
#include "group_state.h"
|
|
#include "stack_utils.h"
|
|
#include "str_utils.h"
|
|
|
|
typedef struct {
|
|
GroupState* group_state;
|
|
AMbyteSpan actor_id_str;
|
|
uint8_t* actor_id_bytes;
|
|
size_t actor_id_size;
|
|
} TestState;
|
|
|
|
static int setup(void** state) {
|
|
TestState* test_state = test_calloc(1, sizeof(TestState));
|
|
group_setup((void**)&test_state->group_state);
|
|
test_state->actor_id_str.src = "000102030405060708090a0b0c0d0e0f";
|
|
test_state->actor_id_str.count = strlen(test_state->actor_id_str.src);
|
|
test_state->actor_id_size = test_state->actor_id_str.count / 2;
|
|
test_state->actor_id_bytes = test_malloc(test_state->actor_id_size);
|
|
hex_to_bytes(test_state->actor_id_str.src, test_state->actor_id_bytes, test_state->actor_id_size);
|
|
*state = test_state;
|
|
return 0;
|
|
}
|
|
|
|
static int teardown(void** state) {
|
|
TestState* test_state = *state;
|
|
group_teardown((void**)&test_state->group_state);
|
|
test_free(test_state->actor_id_bytes);
|
|
test_free(test_state);
|
|
return 0;
|
|
}
|
|
|
|
static void test_AMkeys_empty() {
|
|
AMresultStack* stack = NULL;
|
|
AMdoc* const doc = AMpush(&stack, AMcreate(NULL), AM_VALUE_DOC, cmocka_cb).doc;
|
|
AMstrs forward = AMpush(&stack,
|
|
AMkeys(doc, AM_ROOT, NULL),
|
|
AM_VALUE_STRS,
|
|
cmocka_cb).strs;
|
|
assert_int_equal(AMstrsSize(&forward), 0);
|
|
AMstrs reverse = AMstrsReversed(&forward);
|
|
assert_int_equal(AMstrsSize(&reverse), 0);
|
|
assert_null(AMstrsNext(&forward, 1).src);
|
|
assert_null(AMstrsPrev(&forward, 1).src);
|
|
assert_null(AMstrsNext(&reverse, 1).src);
|
|
assert_null(AMstrsPrev(&reverse, 1).src);
|
|
AMfreeStack(&stack);
|
|
}
|
|
|
|
static void test_AMkeys_list() {
|
|
AMresultStack* stack = NULL;
|
|
AMdoc* const doc = AMpush(&stack, AMcreate(NULL), AM_VALUE_DOC, cmocka_cb).doc;
|
|
AMfree(AMlistPutInt(doc, AM_ROOT, 0, true, 1));
|
|
AMfree(AMlistPutInt(doc, AM_ROOT, 1, true, 2));
|
|
AMfree(AMlistPutInt(doc, AM_ROOT, 2, true, 3));
|
|
AMstrs forward = AMpush(&stack,
|
|
AMkeys(doc, AM_ROOT, NULL),
|
|
AM_VALUE_STRS,
|
|
cmocka_cb).strs;
|
|
assert_int_equal(AMstrsSize(&forward), 3);
|
|
AMstrs reverse = AMstrsReversed(&forward);
|
|
assert_int_equal(AMstrsSize(&reverse), 3);
|
|
/* Forward iterator forward. */
|
|
AMbyteSpan str = AMstrsNext(&forward, 1);
|
|
assert_ptr_equal(strstr(str.src, "1@"), str.src);
|
|
str = AMstrsNext(&forward, 1);
|
|
assert_ptr_equal(strstr(str.src, "2@"), str.src);
|
|
str = AMstrsNext(&forward, 1);
|
|
assert_ptr_equal(strstr(str.src, "3@"), str.src);
|
|
assert_null(AMstrsNext(&forward, 1).src);
|
|
/* Forward iterator reverse. */
|
|
str = AMstrsPrev(&forward, 1);
|
|
assert_ptr_equal(strstr(str.src, "3@"), str.src);
|
|
str = AMstrsPrev(&forward, 1);
|
|
assert_ptr_equal(strstr(str.src, "2@"), str.src);
|
|
str = AMstrsPrev(&forward, 1);
|
|
assert_ptr_equal(strstr(str.src, "1@"), str.src);
|
|
assert_null(AMstrsPrev(&forward, 1).src);
|
|
/* Reverse iterator forward. */
|
|
str = AMstrsNext(&reverse, 1);
|
|
assert_ptr_equal(strstr(str.src, "3@"), str.src);
|
|
str = AMstrsNext(&reverse, 1);
|
|
assert_ptr_equal(strstr(str.src, "2@"), str.src);
|
|
str = AMstrsNext(&reverse, 1);
|
|
assert_ptr_equal(strstr(str.src, "1@"), str.src);
|
|
/* Reverse iterator reverse. */
|
|
assert_null(AMstrsNext(&reverse, 1).src);
|
|
str = AMstrsPrev(&reverse, 1);
|
|
assert_ptr_equal(strstr(str.src, "1@"), str.src);
|
|
str = AMstrsPrev(&reverse, 1);
|
|
assert_ptr_equal(strstr(str.src, "2@"), str.src);
|
|
str = AMstrsPrev(&reverse, 1);
|
|
assert_ptr_equal(strstr(str.src, "3@"), str.src);
|
|
assert_null(AMstrsPrev(&reverse, 1).src);
|
|
AMfreeStack(&stack);
|
|
}
|
|
|
|
static void test_AMkeys_map() {
|
|
AMresultStack* stack = NULL;
|
|
AMdoc* const doc = AMpush(&stack, AMcreate(NULL), AM_VALUE_DOC, cmocka_cb).doc;
|
|
AMfree(AMmapPutInt(doc, AM_ROOT, AMstr("one"), 1));
|
|
AMfree(AMmapPutInt(doc, AM_ROOT, AMstr("two"), 2));
|
|
AMfree(AMmapPutInt(doc, AM_ROOT, AMstr("three"), 3));
|
|
AMstrs forward = AMpush(&stack,
|
|
AMkeys(doc, AM_ROOT, NULL),
|
|
AM_VALUE_STRS,
|
|
cmocka_cb).strs;
|
|
assert_int_equal(AMstrsSize(&forward), 3);
|
|
AMstrs reverse = AMstrsReversed(&forward);
|
|
assert_int_equal(AMstrsSize(&reverse), 3);
|
|
/* Forward iterator forward. */
|
|
AMbyteSpan str = AMstrsNext(&forward, 1);
|
|
assert_int_equal(str.count, 3);
|
|
assert_memory_equal(str.src, "one", str.count);
|
|
str = AMstrsNext(&forward, 1);
|
|
assert_int_equal(str.count, 5);
|
|
assert_memory_equal(str.src, "three", str.count);
|
|
str = AMstrsNext(&forward, 1);
|
|
assert_int_equal(str.count, 3);
|
|
assert_memory_equal(str.src, "two", str.count);
|
|
assert_null(AMstrsNext(&forward, 1).src);
|
|
/* Forward iterator reverse. */
|
|
str = AMstrsPrev(&forward, 1);
|
|
assert_int_equal(str.count, 3);
|
|
assert_memory_equal(str.src, "two", str.count);
|
|
str = AMstrsPrev(&forward, 1);
|
|
assert_int_equal(str.count, 5);
|
|
assert_memory_equal(str.src, "three", str.count);
|
|
str = AMstrsPrev(&forward, 1);
|
|
assert_int_equal(str.count, 3);
|
|
assert_memory_equal(str.src, "one", str.count);
|
|
assert_null(AMstrsPrev(&forward, 1).src);
|
|
/* Reverse iterator forward. */
|
|
str = AMstrsNext(&reverse, 1);
|
|
assert_int_equal(str.count, 3);
|
|
assert_memory_equal(str.src, "two", str.count);
|
|
str = AMstrsNext(&reverse, 1);
|
|
assert_int_equal(str.count, 5);
|
|
assert_memory_equal(str.src, "three", str.count);
|
|
str = AMstrsNext(&reverse, 1);
|
|
assert_int_equal(str.count, 3);
|
|
assert_memory_equal(str.src, "one", str.count);
|
|
assert_null(AMstrsNext(&reverse, 1).src);
|
|
/* Reverse iterator reverse. */
|
|
str = AMstrsPrev(&reverse, 1);
|
|
assert_int_equal(str.count, 3);
|
|
assert_memory_equal(str.src, "one", str.count);
|
|
str = AMstrsPrev(&reverse, 1);
|
|
assert_int_equal(str.count, 5);
|
|
assert_memory_equal(str.src, "three", str.count);
|
|
str = AMstrsPrev(&reverse, 1);
|
|
assert_int_equal(str.count, 3);
|
|
assert_memory_equal(str.src, "two", str.count);
|
|
assert_null(AMstrsPrev(&reverse, 1).src);
|
|
AMfreeStack(&stack);
|
|
}
|
|
|
|
static void test_AMputActor_bytes(void **state) {
|
|
TestState* test_state = *state;
|
|
AMactorId const* actor_id = AMpush(&test_state->group_state->stack,
|
|
AMactorIdInitBytes(
|
|
test_state->actor_id_bytes,
|
|
test_state->actor_id_size),
|
|
AM_VALUE_ACTOR_ID,
|
|
cmocka_cb).actor_id;
|
|
AMfree(AMsetActorId(test_state->group_state->doc, actor_id));
|
|
actor_id = AMpush(&test_state->group_state->stack,
|
|
AMgetActorId(test_state->group_state->doc),
|
|
AM_VALUE_ACTOR_ID,
|
|
cmocka_cb).actor_id;
|
|
AMbyteSpan const bytes = AMactorIdBytes(actor_id);
|
|
assert_int_equal(bytes.count, test_state->actor_id_size);
|
|
assert_memory_equal(bytes.src, test_state->actor_id_bytes, bytes.count);
|
|
}
|
|
|
|
static void test_AMputActor_str(void **state) {
|
|
TestState* test_state = *state;
|
|
AMactorId const* actor_id = AMpush(&test_state->group_state->stack,
|
|
AMactorIdInitStr(test_state->actor_id_str),
|
|
AM_VALUE_ACTOR_ID,
|
|
cmocka_cb).actor_id;
|
|
AMfree(AMsetActorId(test_state->group_state->doc, actor_id));
|
|
actor_id = AMpush(&test_state->group_state->stack,
|
|
AMgetActorId(test_state->group_state->doc),
|
|
AM_VALUE_ACTOR_ID,
|
|
cmocka_cb).actor_id;
|
|
AMbyteSpan const str = AMactorIdStr(actor_id);
|
|
assert_int_equal(str.count, test_state->actor_id_str.count);
|
|
assert_memory_equal(str.src, test_state->actor_id_str.src, str.count);
|
|
}
|
|
|
|
static void test_AMspliceText() {
|
|
AMresultStack* stack = NULL;
|
|
AMdoc* const doc = AMpush(&stack, AMcreate(NULL), AM_VALUE_DOC, cmocka_cb).doc;
|
|
AMfree(AMspliceText(doc, AM_ROOT, 0, 0, AMstr("one + ")));
|
|
AMfree(AMspliceText(doc, AM_ROOT, 4, 2, AMstr("two = ")));
|
|
AMfree(AMspliceText(doc, AM_ROOT, 8, 2, AMstr("three")));
|
|
AMbyteSpan const text = AMpush(&stack,
|
|
AMtext(doc, AM_ROOT, NULL),
|
|
AM_VALUE_STR,
|
|
cmocka_cb).str;
|
|
static char const* const TEXT_VALUE = "one two three";
|
|
assert_int_equal(text.count, strlen(TEXT_VALUE));
|
|
assert_memory_equal(text.src, TEXT_VALUE, text.count);
|
|
AMfreeStack(&stack);
|
|
}
|
|
|
|
int run_doc_tests(void) {
|
|
const struct CMUnitTest tests[] = {
|
|
cmocka_unit_test(test_AMkeys_empty),
|
|
cmocka_unit_test(test_AMkeys_list),
|
|
cmocka_unit_test(test_AMkeys_map),
|
|
cmocka_unit_test_setup_teardown(test_AMputActor_bytes, setup, teardown),
|
|
cmocka_unit_test_setup_teardown(test_AMputActor_str, setup, teardown),
|
|
cmocka_unit_test(test_AMspliceText),
|
|
};
|
|
|
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
|
}
|