8de2fa9bd4
The AMvalue union, AMlistItem struct, AMmapItem struct, and AMobjItem struct are gone, replaced by the AMitem struct. The AMchangeHashes, AMchanges, AMlistItems, AMmapItems, AMobjItems, AMstrs, and AMsyncHaves iterators are gone, replaced by the AMitems iterator. The AMitem struct is opaque, getting and setting values is now achieved exclusively through function calls. The AMitemsNext(), AMitemsPrev(), and AMresultItem() functions return a pointer to an AMitem struct so you ultimately get the same thing whether you're iterating over a sequence or calling AMmapGet() or AMlistGet(). Calling AMitemResult() on an AMitem struct will produce a new AMresult struct referencing its storage so now the AMresult struct for an iterator can be subsequently freed without affecting the AMitem structs that were filtered out of it. The storage for a set of AMitem structs can be recombined into a single AMresult struct by passing pointers to their corresponding AMresult structs to AMresultCat(). For C/C++ programmers, I've added AMstrCmp(), AMstrdup(), AM{idxType,objType,status,valType}ToString() and AM{idxType,objType,status,valType}FromString(). It's also now possible to pass arbitrary parameters through AMstack{Item,Items,Result}() to a callback function.
88 lines
3.1 KiB
C
88 lines
3.1 KiB
C
#include <setjmp.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
|
|
/* third-party */
|
|
#include <automerge-c/utils/enum_string.h>
|
|
#include <automerge-c/utils/stack_callback_data.h>
|
|
#include <automerge-c/utils/string.h>
|
|
#include <cmocka.h>
|
|
|
|
/* local */
|
|
#include "cmocka_utils.h"
|
|
|
|
/**
|
|
* \brief Assert that the given expression is true and report failure in terms
|
|
* of a line number within a file.
|
|
*
|
|
* \param[in] c An expression.
|
|
* \param[in] file A file's full path string.
|
|
* \param[in] line A line number.
|
|
*/
|
|
#define assert_true_where(c, file, line) _assert_true(cast_ptr_to_largest_integral_type(c), #c, file, line)
|
|
|
|
/**
|
|
* \brief Assert that the given pointer is non-NULL and report failure in terms
|
|
* of a line number within a file.
|
|
*
|
|
* \param[in] c An expression.
|
|
* \param[in] file A file's full path string.
|
|
* \param[in] line A line number.
|
|
*/
|
|
#define assert_non_null_where(c, file, line) assert_true_where(c, file, line)
|
|
|
|
/**
|
|
* \brief Forces the test to fail immediately and quit, printing the reason in
|
|
* terms of a line number within a file.
|
|
*
|
|
* \param[in] msg A message string into which \p str is interpolated.
|
|
* \param[in] str An owned string.
|
|
* \param[in] file A file's full path string.
|
|
* \param[in] line A line number.
|
|
*/
|
|
#define fail_msg_where(msg, str, file, line) \
|
|
do { \
|
|
print_error("ERROR: " msg "\n", str); \
|
|
_fail(file, line); \
|
|
} while (0)
|
|
|
|
/**
|
|
* \brief Forces the test to fail immediately and quit, printing the reason in
|
|
* terms of a line number within a file.
|
|
*
|
|
* \param[in] msg A message string into which \p view.src is interpolated.
|
|
* \param[in] view A UTF-8 string view as an `AMbyteSpan` struct.
|
|
* \param[in] file A file's full path string.
|
|
* \param[in] line A line number.
|
|
*/
|
|
#define fail_msg_view_where(msg, view, file, line) \
|
|
do { \
|
|
char* const str = AMstrdup(view, NULL); \
|
|
print_error("ERROR: " msg "\n", str); \
|
|
free(str); \
|
|
_fail(file, line); \
|
|
} while (0)
|
|
|
|
bool cmocka_cb(AMstack** stack, void* data) {
|
|
assert_non_null(data);
|
|
AMstackCallbackData* const sc_data = (AMstackCallbackData*)data;
|
|
assert_non_null_where(stack, sc_data->file, sc_data->line);
|
|
assert_non_null_where(*stack, sc_data->file, sc_data->line);
|
|
assert_non_null_where((*stack)->result, sc_data->file, sc_data->line);
|
|
if (AMresultStatus((*stack)->result) != AM_STATUS_OK) {
|
|
fail_msg_view_where("%s", AMresultError((*stack)->result), sc_data->file, sc_data->line);
|
|
return false;
|
|
}
|
|
/* Test that the types of all item values are members of the mask. */
|
|
AMitems items = AMresultItems((*stack)->result);
|
|
AMitem* item = NULL;
|
|
while ((item = AMitemsNext(&items, 1)) != NULL) {
|
|
AMvalType const tag = AMitemValType(item);
|
|
if (!(tag & sc_data->bitmask)) {
|
|
fail_msg_where("Unexpected value type `%s`.", AMvalTypeToString(tag), sc_data->file, sc_data->line);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|