Merge pull request #300 from jkankiewicz/c_api_exp
Add unit test suites for the `AMlistSet*` and `AMmapSet*` functions
This commit is contained in:
commit
f4ba1770a9
8 changed files with 700 additions and 87 deletions
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
///
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
170
automerge-c/test/amlistset_tests.c
Normal file
170
automerge-c/test/amlistset_tests.c
Normal 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);
|
||||
}
|
97
automerge-c/test/ammapset_tests.c
Normal file
97
automerge-c/test/ammapset_tests.c
Normal 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);
|
||||
}
|
18
automerge-c/test/group_state.c
Normal file
18
automerge-c/test/group_state.c
Normal 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;
|
||||
}
|
15
automerge-c/test/group_state.h
Normal file
15
automerge-c/test/group_state.h
Normal 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
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue