Merge pull request from jkankiewicz/c_api_exp

Add unit test suites for the `AMlistSet*` and `AMmapSet*` functions
This commit is contained in:
Orion Henry 2022-03-09 12:05:58 -05:00 committed by GitHub
commit f4ba1770a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 700 additions and 87 deletions

View file

@ -178,6 +178,8 @@ if(DOXYGEN_FOUND)
set(DOXYGEN_PROJECT_LOGO "${CMAKE_SOURCE_DIR}/img/brandmark.png")
set(DOXYGEN_SORT_BRIEF_DOCS YES)
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md")
doxygen_add_docs(

View file

@ -11,12 +11,13 @@ use result::AMresult;
/// \ingroup enumerations
/// \enum AmObjType
/// \brief The type of an object value.
#[repr(u8)]
pub enum AmObjType {
/// A key/value map.
Map,
/// A list.
List,
List = 1,
/// A key-value map.
Map,
/// A list of Unicode graphemes.
Text,
}
@ -31,23 +32,24 @@ impl From<AmObjType> for am::ObjType {
}
}
/// \ingroup enumerations
/// \enum AmStatus
/// \brief The status of an API call.
#[derive(Debug)]
#[repr(u8)]
pub enum AmStatus {
/// The result is one or more changes.
ChangesOk = 1,
/// The command was successful.
CommandOk,
/// The result was an error.
Error,
/// The result is invalid.
InvalidResult,
/// The result is an object ID.
ObjOk,
/// The result is one or more values.
ValuesOk,
/// The result is one or more changes.
ChangesOk,
/// The result is invalid.
InvalidResult,
/// The result was an error.
Error,
}
unsafe fn to_str(c: *const c_char) -> String {
@ -139,11 +141,11 @@ pub unsafe extern "C" fn AMdup(doc: *mut AMdoc) -> *mut AMdoc {
}
/// \memberof AMdoc
/// \brief Sets a configuration property of an `AMdoc` struct.
/// \brief Set a configuration property of an `AMdoc` struct.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] key A configuration property's key string.
/// \param[in] value A configuration property's string value or `NULL`.
/// \param[in] key A configuration property's UTF-8 string key.
/// \param[in] value A configuration property's UTF-8 string value or `NULL`.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre \p key must be a valid address.
@ -180,7 +182,7 @@ pub unsafe extern "C" fn AMconfig(
/// \brief Get an `AMdoc` struct's actor ID value as a hexadecimal string.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \return A pointer to an `AMresult` struct containing a string value.
/// \return A pointer to an `AMresult` struct containing a UTF-8 string value.
/// \pre \p doc must be a valid address.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
@ -216,12 +218,12 @@ pub unsafe extern "C" fn AMresultStatus(result: *mut AMresult) -> AmStatus {
}
/// \memberof AMdoc
/// \brief Set a map object's value.
/// \brief Set a map object's key to a signed integer value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] key A map object's key string.
/// \param[in] value A 64 bit int
/// \param[in] key A UTF-8 string key for the map object identified by \p obj.
/// \param[in] value A 64-bit signed integer.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre \p key must be a valid address.
@ -245,12 +247,12 @@ pub unsafe extern "C" fn AMmapSetInt(
}
/// \memberof AMdoc
/// \brief Set a map object's value.
/// \brief Set a map object's key to an unsigned integer value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] key A map object's key string.
/// \param[in] value A 64 bit uint
/// \param[in] key A UTF-8 string key for the map object identified by \p obj.
/// \param[in] value A 64-bit unsigned integer.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre \p key must be a valid address.
@ -274,15 +276,16 @@ pub unsafe extern "C" fn AMmapSetUint(
}
/// \memberof AMdoc
/// \brief Set a map object's value.
/// \brief Set a map object's key to a UTF-8 string value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] key A map object's key string.
/// \param[in] value A valid c string
/// \param[in] key A UTF-8 string key for the map object identified by \p obj.
/// \param[in] value A UTF-8 string.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre \p key must be a valid address.
/// \pre \p value must be a valid address.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
@ -303,16 +306,18 @@ pub unsafe extern "C" fn AMmapSetStr(
}
/// \memberof AMdoc
/// \brief Set a map object's value.
/// \brief Set a map object's key to a byte array value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] key A map object's key string.
/// \param[in] value A byte array
/// \param[in] length A size_t length of the byte array
/// \param[in] key A UTF-8 string key for the map object identified by \p obj.
/// \param[in] value A pointer to an array of bytes.
/// \param[in] count The number of bytes to copy from \p value.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre \p key must be a valid address.
/// \pre \p value must be a valid address.
/// \pre `0 <=` \p count `<=` length of \p value.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
@ -320,30 +325,30 @@ pub unsafe extern "C" fn AMmapSetStr(
/// # Safety
/// doc must be a pointer to a valid AMdoc
/// obj must be a pointer to a valid AMobj or NULL
/// value must be a byte array of length `count`
/// key must be a c string of the map key to be used
/// value must be a byte array of lenth `length`
#[no_mangle]
pub unsafe extern "C" fn AMmapSetBytes(
doc: *mut AMdoc,
obj: *mut AMobj,
key: *const c_char,
value: *const u8,
length: usize,
count: usize,
) -> *mut AMresult {
let doc = to_doc!(doc);
let slice = std::slice::from_raw_parts(value, length);
let slice = std::slice::from_raw_parts(value, count);
let mut vec = Vec::new();
vec.extend_from_slice(slice);
to_result(doc.set(to_obj!(obj), to_str(key), vec))
}
/// \memberof AMdoc
/// \brief Set a map object's value.
/// \brief Set a map object's key to a float value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] key A map object's key string.
/// \param[in] value A double
/// \param[in] key A UTF-8 string key for the map object identified by \p obj.
/// \param[in] value A 64-bit float.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre \p key must be a valid address.
@ -367,12 +372,12 @@ pub unsafe extern "C" fn AMmapSetF64(
}
/// \memberof AMdoc
/// \brief Set a map object's value.
/// \brief Set a map object's key to a CRDT counter value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] key A map object's key string.
/// \param[in] value A 64 bit int
/// \param[in] key A UTF-8 string key for the map object identified by \p obj.
/// \param[in] value A 64-bit signed integer.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre \p key must be a valid address.
@ -400,12 +405,12 @@ pub unsafe extern "C" fn AMmapSetCounter(
}
/// \memberof AMdoc
/// \brief Set a map object's value.
/// \brief Set a map object's key to a Lamport timestamp value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] key A map object's key string.
/// \param[in] value A 64 bit int
/// \param[in] key A UTF-8 string key for the map object identified by \p obj.
/// \param[in] value A 64-bit signed integer.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre \p key must be a valid address.
@ -429,11 +434,11 @@ pub unsafe extern "C" fn AMmapSetTimestamp(
}
/// \memberof AMdoc
/// \brief Set a map object's value.
/// \brief Set a map object's key to a null value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] key A map object's key string.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre \p key must be a valid address.
@ -456,13 +461,13 @@ pub unsafe extern "C" fn AMmapSetNull(
}
/// \memberof AMdoc
/// \brief Set a map object's value.
/// \brief Set a map object's key to an empty object value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] key A map object's key string.
/// \param[in] objtype A valid AmObjType enum
/// \return A pointer to an `AMresult` struct containing no value.
/// \param[in] key A UTF-8 string key for the map object identified by \p obj.
/// \param[in] obj_type An `AmObjType` enum tag.
/// \return A pointer to an `AMresult` struct containing a pointer to an `AMobj` struct.
/// \pre \p doc must be a valid address.
/// \pre \p key must be a valid address.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
@ -478,23 +483,147 @@ pub unsafe extern "C" fn AMmapSetObject(
doc: *mut AMdoc,
obj: *mut AMobj,
key: *const c_char,
objtype: AmObjType,
obj_type: AmObjType,
) -> *mut AMresult {
let doc = to_doc!(doc);
to_result(doc.set_object(to_obj!(obj), to_str(key), objtype.into()))
to_result(doc.set_object(to_obj!(obj), to_str(key), obj_type.into()))
}
/// \memberof AMdoc
/// \brief Set a list object's value.
/// \brief Set a list object's index to a byte array value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] index A list object's index number.
/// \param[in] insert A boolean to insert or overrite at the index
/// \param[in] value An i64 value
/// \param[in] index An index within the list object identified by \p obj.
/// \param[in] insert A flag to insert \p value before \p index instead of writing \p value over \p index.
/// \param[in] value A pointer to an array of bytes.
/// \param[in] count The number of bytes to copy from \p value.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre \p obj must be a valid address.
/// \pre `0 <=` \p index `<=` length of the list object identified by \p obj.
/// \pre \p value must be a valid address.
/// \pre `0 <=` \p count `<=` length of \p value.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
///
/// # Safety
/// doc must be a pointer to a valid AMdoc
/// obj must be a pointer to a valid AMobj or NULL
/// value must be a byte array of length `count`
/// key must be a c string of the map key to be used
#[no_mangle]
pub unsafe extern "C" fn AMlistSetBytes(
doc: *mut AMdoc,
obj: *mut AMobj,
index: usize,
insert: bool,
value: *const u8,
count: usize,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj = to_obj!(obj);
let slice = std::slice::from_raw_parts(value, count);
let mut vec = Vec::new();
vec.extend_from_slice(slice);
to_result(
if insert {
doc.insert(obj, index, vec)
}
else {
doc.set(obj, index, vec)
}
)
}
/// \memberof AMdoc
/// \brief Set a list object's index to a CRDT counter value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] index An index within the list object identified by \p obj.
/// \param[in] insert A flag to insert \p value before \p index instead of writing \p value over \p index.
/// \param[in] value A 64-bit signed integer.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre `0 <=` \p index `<=` length of the list object identified by \p obj.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
///
/// # Safety
/// doc must be a pointer to a valid AMdoc
/// obj must be a pointer to a valid AMobj or NULL
#[no_mangle]
pub unsafe extern "C" fn AMlistSetCounter(
doc: *mut AMdoc,
obj: *mut AMobj,
index: usize,
insert: bool,
value: i64,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj = to_obj!(obj);
let value = am::ScalarValue::Counter(value.into());
to_result(
if insert {
doc.insert(obj, index, value)
}
else {
doc.set(obj, index, value)
}
)
}
/// \memberof AMdoc
/// \brief Set a list object's index to a float value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] index An index within the list object identified by \p obj.
/// \param[in] insert A flag to insert \p value before \p index instead of writing \p value over \p index.
/// \param[in] value A 64-bit float.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre `0 <=` \p index `<=` length of the list object identified by \p obj.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
///
/// # Safety
/// doc must be a pointer to a valid AMdoc
/// obj must be a pointer to a valid AMobj or NULL
#[no_mangle]
pub unsafe extern "C" fn AMlistSetF64(
doc: *mut AMdoc,
obj: *mut AMobj,
index: usize,
insert: bool,
value: f64,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj = to_obj!(obj);
to_result(
if insert {
doc.insert(obj, index, value)
}
else {
doc.set(obj, index, value)
}
)
}
/// \memberof AMdoc
/// \brief Set a list object's index to a signed integer value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] index An index within the list object identified by \p obj.
/// \param[in] insert A flag to insert \p value before \p index instead of writing \p value over \p index.
/// \param[in] value A 64-bit signed integer.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre `0 <=` \p index `<=` length of the list object identified by \p obj.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
@ -502,7 +631,6 @@ pub unsafe extern "C" fn AMmapSetObject(
/// # Safety
/// doc must be a pointer to a valid AMdoc
/// obj must be a pointer to a valid AMobj or NULL
/// value must be a pointer to data of the type specified in data_type
#[no_mangle]
pub unsafe extern "C" fn AMlistSetInt(
doc: *mut AMdoc,
@ -513,11 +641,208 @@ pub unsafe extern "C" fn AMlistSetInt(
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj = to_obj!(obj);
if insert {
to_result(doc.insert(obj, index, value))
} else {
to_result(doc.set(obj, index, value))
}
to_result(
if insert {
doc.insert(obj, index, value)
}
else {
doc.set(obj, index, value)
}
)
}
/// \memberof AMdoc
/// \brief Set a list object's index to a null value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] index An index within the list object identified by \p obj.
/// \param[in] insert A flag to insert \p value before \p index instead of writing \p value over \p index.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre `0 <=` \p index `<=` length of the list object identified by \p obj.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
///
/// # Safety
/// doc must be a pointer to a valid AMdoc
/// obj must be a pointer to a valid AMobj or NULL
#[no_mangle]
pub unsafe extern "C" fn AMlistSetNull(
doc: *mut AMdoc,
obj: *mut AMobj,
index: usize,
insert: bool,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj = to_obj!(obj);
let value = ();
to_result(
if insert {
doc.insert(obj, index, value)
}
else {
doc.set(obj, index, value)
}
)
}
/// \memberof AMdoc
/// \brief Set a list object's index to an empty object value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] index An index within the list object identified by \p obj.
/// \param[in] insert A flag to insert \p value before \p index instead of writing \p value over \p index.
/// \param[in] obj_type An `AmObjType` enum tag.
/// \return A pointer to an `AMresult` struct containing a pointer to an `AMobj` struct.
/// \pre \p doc must be a valid address.
/// \pre `0 <=` \p index `<=` length of the list object identified by \p obj.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
///
/// # Safety
/// doc must be a pointer to a valid AMdoc
/// obj must be a pointer to a valid AMobj or NULL
#[no_mangle]
pub unsafe extern "C" fn AMlistSetObject(
doc: *mut AMdoc,
obj: *mut AMobj,
index: usize,
insert: bool,
obj_type: AmObjType,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj = to_obj!(obj);
let value = obj_type.into();
to_result(
if insert {
doc.insert_object(obj, index, value)
}
else {
doc.set_object(obj, index, value)
}
)
}
/// \memberof AMdoc
/// \brief Set a list object's index to a UTF-8 string value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] index An index within the list object identified by \p obj.
/// \param[in] insert A flag to insert \p value before \p index instead of writing \p value over \p index.
/// \param[in] value A UTF-8 string.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre `0 <=` \p index `<=` length of the list object identified by \p obj.
/// \pre \p value must be a valid address.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
///
/// # Safety
/// doc must be a pointer to a valid AMdoc
/// obj must be a pointer to a valid AMobj or NULL
/// value must be a pointer to a valid address.
#[no_mangle]
pub unsafe extern "C" fn AMlistSetStr(
doc: *mut AMdoc,
obj: *mut AMobj,
index: usize,
insert: bool,
value: *const c_char,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj = to_obj!(obj);
let value = to_str(value);
to_result(
if insert {
doc.insert(obj, index, value)
}
else {
doc.set(obj, index, value)
}
)
}
/// \memberof AMdoc
/// \brief Set a list object's index to a Lamport timestamp value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] index An index within the list object identified by \p obj.
/// \param[in] insert A flag to insert \p value before \p index instead of writing \p value over \p index.
/// \param[in] value A 64-bit signed integer.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre `0 <=` \p index `<=` length of the list object identified by \p obj.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
///
/// # Safety
/// doc must be a pointer to a valid AMdoc
/// obj must be a pointer to a valid AMobj or NULL
#[no_mangle]
pub unsafe extern "C" fn AMlistSetTimestamp(
doc: *mut AMdoc,
obj: *mut AMobj,
index: usize,
insert: bool,
value: i64,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj = to_obj!(obj);
let value = am::ScalarValue::Timestamp(value);
to_result(
if insert {
doc.insert(obj, index, value)
}
else {
doc.set(obj, index, value)
}
)
}
/// \memberof AMdoc
/// \brief Set a list object's index to an unsigned integer value.
///
/// \param[in] doc A pointer to an `AMdoc` struct.
/// \param[in] obj A pointer to an `AMobj` struct or `NULL`.
/// \param[in] index An index within the list object identified by \p obj.
/// \param[in] insert A flag to insert \p value before \p index instead of writing \p value over \p index.
/// \param[in] value A 64-bit unsigned integer.
/// \return A pointer to an `AMresult` struct containing no value.
/// \pre \p doc must be a valid address.
/// \pre `0 <=` \p index `<=` length of the list object identified by \p obj.
/// \warning To avoid a memory leak, the returned pointer must be deallocated
/// with `AMclear()`.
/// \internal
///
/// # Safety
/// doc must be a pointer to a valid AMdoc
/// obj must be a pointer to a valid AMobj or NULL
#[no_mangle]
pub unsafe extern "C" fn AMlistSetUint(
doc: *mut AMdoc,
obj: *mut AMobj,
index: usize,
insert: bool,
value: u64,
) -> *mut AMresult {
let doc = to_doc!(doc);
let obj = to_obj!(obj);
to_result(
if insert {
doc.insert(obj, index, value)
}
else {
doc.set(obj, index, value)
}
)
}
/// \memberof AMresult
@ -556,7 +881,7 @@ pub unsafe extern "C" fn AMclear(result: *mut AMresult) {
/// \brief Get an `AMresult` struct's error message string.
///
/// \param[in] result A pointer to an `AMresult` struct.
/// \return A string value or `NULL`.
/// \return A UTF-8 string value or `NULL`.
/// \pre \p result must be a valid address.
/// \internal
///

View file

@ -2,7 +2,13 @@ cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
find_package(cmocka REQUIRED)
add_executable(test_${LIBRARY_NAME} main.c)
add_executable(
test_${LIBRARY_NAME}
group_state.c
amlistset_tests.c
ammapset_tests.c
main.c
)
set_target_properties(test_${LIBRARY_NAME} PROPERTIES LINKER_LANGUAGE C)

View file

@ -0,0 +1,170 @@
#include <float.h>
#include <limits.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
/* third-party */
#include <cmocka.h>
/* local */
#include "group_state.h"
#define test_AMlistSet(label, mode) test_AMlistSet ## label ## _ ## mode
#define static_void_test_AMlistSet(label, mode, value) \
static void test_AMlistSet ## label ## _ ## mode(void **state) { \
GroupState* group_state = *state; \
AMresult* res = AMlistSet ## label(group_state->doc, AM_ROOT, 0, !strcmp(#mode, "insert"), value); \
if (AMresultStatus(res) != AM_STATUS_COMMAND_OK) { \
fail_msg("%s", AMerrorMessage(res)); \
} \
}
static_void_test_AMlistSet(Counter, insert, INT64_MAX)
static_void_test_AMlistSet(Counter, update, INT64_MAX)
static_void_test_AMlistSet(F64, insert, DBL_MAX)
static_void_test_AMlistSet(F64, update, DBL_MAX)
static_void_test_AMlistSet(Int, insert, INT64_MAX)
static_void_test_AMlistSet(Int, update, INT64_MAX)
static_void_test_AMlistSet(Str, insert, "Hello, world!")
static_void_test_AMlistSet(Str, update, "Hello, world!")
static_void_test_AMlistSet(Timestamp, insert, INT64_MAX)
static_void_test_AMlistSet(Timestamp, update, INT64_MAX)
static_void_test_AMlistSet(Uint, insert, UINT64_MAX)
static_void_test_AMlistSet(Uint, update, UINT64_MAX)
static void test_AMlistSetBytes_insert(void **state) {
static uint8_t const BYTES_VALUE[] = {INT8_MIN, INT8_MAX / 2, INT8_MAX};
GroupState* group_state = *state;
AMresult* res = AMlistSetBytes(
group_state->doc,
AM_ROOT,
0,
true,
BYTES_VALUE,
sizeof(BYTES_VALUE) / sizeof(uint8_t)
);
if (AMresultStatus(res) != AM_STATUS_COMMAND_OK) {
fail_msg("%s", AMerrorMessage(res));
}
}
static void test_AMlistSetBytes_update(void **state) {
static uint8_t const BYTES_VALUE[] = {INT8_MIN, INT8_MAX / 2, INT8_MAX};
GroupState* group_state = *state;
AMresult* res = AMlistSetBytes(
group_state->doc,
AM_ROOT,
0,
false,
BYTES_VALUE,
sizeof(BYTES_VALUE) / sizeof(uint8_t)
);
if (AMresultStatus(res) != AM_STATUS_COMMAND_OK) {
fail_msg("%s", AMerrorMessage(res));
}
}
static void test_AMlistSetNull_insert(void **state) {
GroupState* group_state = *state;
AMresult* res = AMlistSetNull(group_state->doc, AM_ROOT, 0, true);
if (AMresultStatus(res) != AM_STATUS_COMMAND_OK) {
fail_msg("%s", AMerrorMessage(res));
}
}
static void test_AMlistSetNull_update(void **state) {
GroupState* group_state = *state;
AMresult* res = AMlistSetNull(group_state->doc, AM_ROOT, 0, false);
if (AMresultStatus(res) != AM_STATUS_COMMAND_OK) {
fail_msg("would be consolidated into%s", AMerrorMessage(res));
}
}
static void test_AMlistSetObject_insert(void **state) {
static AmObjType const OBJ_TYPES[] = {
AM_OBJ_TYPE_LIST,
AM_OBJ_TYPE_MAP,
AM_OBJ_TYPE_TEXT,
};
static AmObjType const* const end = OBJ_TYPES + sizeof(OBJ_TYPES) / sizeof(AmObjType);
GroupState* group_state = *state;
for (AmObjType const* next = OBJ_TYPES; next != end; ++next) {
AMresult* res = AMlistSetObject(
group_state->doc,
AM_ROOT,
0,
true,
*next
);
if (AMresultStatus(res) != AM_STATUS_OBJ_OK) {
fail_msg("%s", AMerrorMessage(res));
}
}
}
static void test_AMlistSetObject_update(void **state) {
static AmObjType const OBJ_TYPES[] = {
AM_OBJ_TYPE_LIST,
AM_OBJ_TYPE_MAP,
AM_OBJ_TYPE_TEXT,
};
static AmObjType const* const end = OBJ_TYPES + sizeof(OBJ_TYPES) / sizeof(AmObjType);
GroupState* group_state = *state;
for (AmObjType const* next = OBJ_TYPES; next != end; ++next) {
AMresult* res = AMlistSetObject(
group_state->doc,
AM_ROOT,
0,
false,
*next
);
if (AMresultStatus(res) != AM_STATUS_OBJ_OK) {
fail_msg("%s", AMerrorMessage(res));
}
}
}
int run_AMlistSet_tests(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_AMlistSetBytes_insert),
cmocka_unit_test(test_AMlistSetBytes_update),
cmocka_unit_test(test_AMlistSet(Counter, insert)),
cmocka_unit_test(test_AMlistSet(Counter, update)),
cmocka_unit_test(test_AMlistSet(F64, insert)),
cmocka_unit_test(test_AMlistSet(F64, update)),
cmocka_unit_test(test_AMlistSet(Int, insert)),
cmocka_unit_test(test_AMlistSet(Int, update)),
cmocka_unit_test(test_AMlistSetNull_insert),
cmocka_unit_test(test_AMlistSetNull_update),
cmocka_unit_test(test_AMlistSetObject_insert),
cmocka_unit_test(test_AMlistSetObject_update),
cmocka_unit_test(test_AMlistSet(Str, insert)),
cmocka_unit_test(test_AMlistSet(Str, update)),
cmocka_unit_test(test_AMlistSet(Timestamp, insert)),
cmocka_unit_test(test_AMlistSet(Timestamp, update)),
cmocka_unit_test(test_AMlistSet(Uint, insert)),
cmocka_unit_test(test_AMlistSet(Uint, update)),
};
return cmocka_run_group_tests(tests, group_setup, group_teardown);
}

View file

@ -0,0 +1,97 @@
#include <float.h>
#include <limits.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
/* third-party */
#include <cmocka.h>
/* local */
#include "group_state.h"
#define test_AMmapSet(label) test_AMmapSet ## label
#define static_void_test_AMmapSet(label, value) \
static void test_AMmapSet ## label(void **state) { \
GroupState* group_state = *state; \
AMresult* res = AMmapSet ## label(group_state->doc, AM_ROOT, #label, value); \
if (AMresultStatus(res) != AM_STATUS_COMMAND_OK) { \
fail_msg("%s", AMerrorMessage(res)); \
} \
}
static_void_test_AMmapSet(Int, INT64_MAX)
static_void_test_AMmapSet(Uint, UINT64_MAX)
static_void_test_AMmapSet(Str, "Hello, world!")
static_void_test_AMmapSet(F64, DBL_MAX)
static_void_test_AMmapSet(Counter, INT64_MAX)
static_void_test_AMmapSet(Timestamp, INT64_MAX)
static void test_AMmapSetBytes(void **state) {
static uint8_t const BYTES_VALUE[] = {INT8_MIN, INT8_MAX / 2, INT8_MAX};
GroupState* group_state = *state;
AMresult* res = AMmapSetBytes(
group_state->doc,
AM_ROOT,
"Bytes",
BYTES_VALUE,
sizeof(BYTES_VALUE) / sizeof(uint8_t)
);
if (AMresultStatus(res) != AM_STATUS_COMMAND_OK) {
fail_msg("%s", AMerrorMessage(res));
}
}
static void test_AMmapSetNull(void **state) {
GroupState* group_state = *state;
AMresult* res = AMmapSetNull(group_state->doc, AM_ROOT, "Null");
if (AMresultStatus(res) != AM_STATUS_COMMAND_OK) {
fail_msg("%s", AMerrorMessage(res));
}
}
static void test_AMmapSetObject(void **state) {
static AmObjType const OBJ_TYPES[] = {
AM_OBJ_TYPE_LIST,
AM_OBJ_TYPE_MAP,
AM_OBJ_TYPE_TEXT,
};
static AmObjType const* const end = OBJ_TYPES + sizeof(OBJ_TYPES) / sizeof(AmObjType);
GroupState* group_state = *state;
for (AmObjType const* next = OBJ_TYPES; next != end; ++next) {
AMresult* res = AMmapSetObject(
group_state->doc,
AM_ROOT,
"Object",
*next
);
if (AMresultStatus(res) != AM_STATUS_OBJ_OK) {
fail_msg("%s", AMerrorMessage(res));
}
}
}
int run_AMmapSet_tests(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_AMmapSetBytes),
cmocka_unit_test(test_AMmapSet(Counter)),
cmocka_unit_test(test_AMmapSet(F64)),
cmocka_unit_test(test_AMmapSet(Int)),
cmocka_unit_test(test_AMmapSetNull),
cmocka_unit_test(test_AMmapSetObject),
cmocka_unit_test(test_AMmapSet(Str)),
cmocka_unit_test(test_AMmapSet(Timestamp)),
cmocka_unit_test(test_AMmapSet(Uint)),
};
return cmocka_run_group_tests(tests, group_setup, group_teardown);
}

View file

@ -0,0 +1,18 @@
#include <stdlib.h>
/* local */
#include "group_state.h"
int group_setup(void** state) {
GroupState* group_state = calloc(1, sizeof(GroupState));
group_state->doc = AMcreate();
*state = group_state;
return 0;
}
int group_teardown(void** state) {
GroupState* group_state = *state;
AMdestroy(group_state->doc);
free(group_state);
return 0;
}

View file

@ -0,0 +1,15 @@
#ifndef GROUP_STATE_INCLUDED
#define GROUP_STATE_INCLUDED
/* local */
#include "automerge.h"
typedef struct {
AMdoc* doc;
} GroupState;
int group_setup(void** state);
int group_teardown(void** state);
#endif

View file

@ -1,6 +1,5 @@
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <setjmp.h>
#include <stdint.h>
@ -8,44 +7,25 @@
#include <cmocka.h>
/* local */
#include "automerge.h"
#include "group_state.h"
typedef struct {
AMdoc* doc;
} GroupState;
extern int run_AMlistSet_tests(void);
static int group_setup(void** state) {
GroupState* group_state = calloc(1, sizeof(GroupState));
group_state->doc = AMcreate();
*state = group_state;
return 0;
}
static int group_teardown(void** state) {
GroupState* group_state = *state;
AMdestroy(group_state->doc);
free(group_state);
return 0;
}
extern int run_AMmapSet_tests(void);
static void test_AMconfig(void **state) {
GroupState* group_state = *state;
AMconfig(group_state->doc, "actor", "aabbcc");
}
static void test_AMmapSetStr(void **state) {
GroupState* group_state = *state;
AMresult* res = AMmapSetStr(group_state->doc, NULL, "string", "hello world");
if (AMresultStatus(res) != AM_STATUS_COMMAND_OK) {
fail_msg("%s", AMerrorMessage(res));
}
}
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_AMconfig),
cmocka_unit_test(test_AMmapSetStr),
};
return cmocka_run_group_tests(tests, group_setup, group_teardown);
return (
run_AMlistSet_tests() +
run_AMmapSet_tests() +
cmocka_run_group_tests(tests, group_setup, group_teardown)
);
}