~alextee/zrythm-cyaml

3a113fa492a9ff35384b04f3133761241e88e28a — Alexandros Theodotou 3 years ago 30e5e30
apply float overflow fix from upstream
M Makefile => Makefile +5 -2
@@ 8,7 8,7 @@
VERSION_MAJOR = 1
VERSION_MINOR = 1
VERSION_PATCH = 0
VERSION_DEVEL = 0
VERSION_DEVEL = 1
VERSION_STR = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)

# Default variant depends on whether it's a development build.


@@ 56,7 56,10 @@ LIBYAML_LIBS := $(if $(PKG_CONFIG),$(shell $(PKG_CONFIG) --libs $(LIBYAML)),-lya

INCLUDE = -I include
CFLAGS += $(INCLUDE) $(VERSION_FLAGS) $(LIBYAML_CFLAGS)
CFLAGS += -std=c11 -Wall -Wextra -pedantic -Wconversion
CFLAGS += -std=c11 -Wall -Wextra -pedantic \
		-Wconversion -Wwrite-strings -Wcast-align -Wpointer-arith \
		-Winit-self -Wshadow -Wstrict-prototypes -Wmissing-prototypes \
		-Wredundant-decls -Wundef -Wvla -Wdeclaration-after-statement
LDFLAGS += $(LIBYAML_LIBS)
LDFLAGS_SHARED += -Wl,-soname=$(LIB_SH_MAJ) -shared


M include/cyaml/cyaml.h => include/cyaml/cyaml.h +4 -1
@@ 183,7 183,10 @@ typedef enum cyaml_flag {
	 * * For \ref CYAML_ENUM, the value becomes the value of the enum.
	 *   The numerical value is treated as signed.
	 * * For \ref CYAML_FLAGS, the values are bitwise ORed together.
	 *   The numerical values are treated as unsigned,
	 *   The numerical values are treated as unsigned.
	 *
	 * For \ref CYAML_FLOAT types, in strict mode floating point values
	 * that would cause overflow or underflow are not permitted.
	 */
	CYAML_FLAG_STRICT   = (1 << 4),
	/**

M src/data.h => src/data.h +6 -4
@@ 58,8 58,9 @@ static inline void cyaml_data_write_pointer(
{
	/* Refuse to build on platforms where sizeof pointer would
	 * lead to \ref CYAML_ERR_INVALID_DATA_SIZE. */
	cyaml_static_assert(sizeof(char *) >  0);
	cyaml_static_assert(sizeof(char *) <= sizeof(uint64_t));
	static_assert(sizeof(char *) >  0, "Incompatible pointer size.");
	static_assert(sizeof(char *) <= sizeof(uint64_t),
			"Incompatible pointer size.");

	CYAML_UNUSED(cyaml_data_write((uint64_t)ptr, sizeof(ptr), data_target));



@@ 115,8 116,9 @@ static inline uint8_t * cyaml_data_read_pointer(

	/* Refuse to build on platforms where sizeof pointer would
	 * lead to \ref CYAML_ERR_INVALID_DATA_SIZE. */
	cyaml_static_assert(sizeof(char *) >  0);
	cyaml_static_assert(sizeof(char *) <= sizeof(uint64_t));
	static_assert(sizeof(char *) >  0, "Incompatible pointer size.");
	static_assert(sizeof(char *) <= sizeof(uint64_t),
			"Incompatible pointer size.");

	return (void *)cyaml_data_read(sizeof(char *), data, &err);
}

M src/load.c => src/load.c +79 -16
@@ 18,6 18,8 @@
#include <assert.h>
#include <limits.h>
#include <errno.h>
#include <float.h>
#include <math.h>

#include <yaml.h>



@@ 639,7 641,6 @@ static void cyaml__handle_replay(
 * object.
 *
 * \param[in]  ctx    The CYAML loading context.
 * \return \ref CYAML_OK on success, or appropriate error otherwise.
 */
static void cyaml__delete_yaml_event(
		cyaml_ctx_t *ctx)


@@ 879,17 880,20 @@ static cyaml_err_t cyaml__mapping_bitfieid_create(
		cyaml_ctx_t *ctx,
		cyaml_state_t *state)
{
	cyaml_bitfield_t *bitfield;
	unsigned count = state->mapping.fields_count;
	size_t size = ((count + CYAML_BITFIELD_BITS - 1) / CYAML_BITFIELD_BITS)
			* sizeof(*bitfield);

	bitfield = cyaml__alloc(ctx->config, size, true);
	if (bitfield == NULL) {
		return CYAML_ERR_OOM;
	}
	if (count != 0) {
		cyaml_bitfield_t *bitfield;
		size_t size = ((count + CYAML_BITFIELD_BITS - 1) /
				CYAML_BITFIELD_BITS) * sizeof(*bitfield);

	state->mapping.fields_set = bitfield;
		bitfield = cyaml__alloc(ctx->config, size, true);
		if (bitfield == NULL) {
			return CYAML_ERR_OOM;
		}

		state->mapping.fields_set = bitfield;
	}

	return CYAML_OK;
}


@@ 1312,6 1316,9 @@ static cyaml_err_t cyaml__read_int(

	if (end == value || errno == ERANGE ||
	    temp < min || temp > max) {
		cyaml__log(ctx->config, CYAML_LOG_ERROR,
				"Load: Invalid INT value: '%s'\n",
				value);
		return CYAML_ERR_INVALID_VALUE;
	}



@@ 1321,11 1328,13 @@ static cyaml_err_t cyaml__read_int(
/**
 * Helper to read a number into a uint64_t.
 *
 * \param[in]  ctx    The CYAML loading context.
 * \param[in]  value  String containing scaler value.
 * \param[in]  out    The place to write the value in the output data.
 * \return \ref CYAML_OK on success, or appropriate error code otherwise.
 */
static inline cyaml_err_t cyaml__read_uint64_t(
		const cyaml_ctx_t *ctx,
		const char *value,
		uint64_t *out)
{


@@ 1336,6 1345,9 @@ static inline cyaml_err_t cyaml__read_uint64_t(
	temp = strtoull(value, &end, 0);

	if (end == value || errno == ERANGE) {
		cyaml__log(ctx->config, CYAML_LOG_ERROR,
				"Load: Invalid uint64_t value: '%s'\n",
				value);
		return CYAML_ERR_INVALID_VALUE;
	}



@@ 1368,13 1380,16 @@ static cyaml_err_t cyaml__read_uint(
		return CYAML_ERR_INVALID_DATA_SIZE;
	}

	err = cyaml__read_uint64_t(value, &temp);
	err = cyaml__read_uint64_t(ctx, value, &temp);
	if (err != CYAML_OK) {
		return err;
	}

	max = (~(uint64_t)0) >> ((8 - schema->data_size) * 8);
	if (temp > max) {
		cyaml__log(ctx->config, CYAML_LOG_ERROR,
				"Load: Invalid UINT value: '%s'\n",
				value);
		return CYAML_ERR_INVALID_VALUE;
	}



@@ 1398,7 1413,7 @@ static cyaml_err_t cyaml__read_bool(
{
	bool temp = true;
	static const char * const false_strings[] = {
		"false", "no", "disable", "0",
		"false", "no", "off", "disable", "0",
	};

	CYAML_UNUSED(ctx);


@@ 1440,11 1455,14 @@ static cyaml_err_t cyaml__read_enum(

	if (schema->flags & CYAML_FLAG_STRICT) {
		cyaml__log(ctx->config, CYAML_LOG_ERROR,
				"Load: Invalid enumeration value: %s\n", value);
				"Load: Invalid ENUM value: %s\n", value);
		return CYAML_ERR_INVALID_VALUE;

	}

	cyaml__log(ctx->config, CYAML_LOG_DEBUG,
			"Load: Attempt numerical fallback for ENUM: "
			"'%s'\n", value);
	return cyaml__read_int(ctx, schema, value, data);
}



@@ 1474,8 1492,31 @@ static cyaml_err_t cyaml__read_float_f(
	errno = 0;
	temp = strtof(value, &end);

	if (end == value || errno == ERANGE) {
	if (end == value) {
		cyaml__log(ctx->config, CYAML_LOG_ERROR,
				"Load: Invalid FLOAT value: %s\n", value);
		return CYAML_ERR_INVALID_VALUE;

	} else if (errno == ERANGE) {
		cyaml_log_t level = CYAML_LOG_ERROR;

		if (!cyaml__flag_check_all(schema->flags, CYAML_FLAG_STRICT)) {
			level = CYAML_LOG_NOTICE;
		}

		if (temp == HUGE_VALF || temp == -HUGE_VALF) {
			cyaml__log(ctx->config, level,
				"Load: FLOAT overflow: %s\n", value);

		} else {
			assert(temp < FLT_MIN || temp > FLT_MAX);
			cyaml__log(ctx->config, level,
				"Load: FLOAT underflow: %s\n", value);
		}

		if (cyaml__flag_check_all(schema->flags, CYAML_FLAG_STRICT)) {
			return CYAML_ERR_INVALID_VALUE;
		}
	}

	memcpy(data, &temp, sizeof(temp));


@@ 1509,8 1550,24 @@ static cyaml_err_t cyaml__read_float_d(
	errno = 0;
	temp = strtod(value, &end);

	if (end == value || errno == ERANGE) {
	if (end == value) {
		cyaml__log(ctx->config, CYAML_LOG_ERROR,
				"Load: Invalid FLOAT value: %s\n", value);
		return CYAML_ERR_INVALID_VALUE;

	} else if (errno == ERANGE) {
		cyaml_log_t level = CYAML_LOG_ERROR;

		if (!cyaml__flag_check_all(schema->flags, CYAML_FLAG_STRICT)) {
			level = CYAML_LOG_NOTICE;
		}

		cyaml__log(ctx->config, level,
				"Load: FLOAT overflow/overflow: %s\n", value);

		if (cyaml__flag_check_all(schema->flags, CYAML_FLAG_STRICT)) {
			return CYAML_ERR_INVALID_VALUE;
		}
	}

	memcpy(data, &temp, sizeof(temp));


@@ 1591,8 1648,14 @@ static cyaml_err_t cyaml__read_string(
	if (schema->string.min > schema->string.max) {
		return CYAML_ERR_BAD_MIN_MAX_SCHEMA;
	} else if (str_len < schema->string.min) {
		cyaml__log(ctx->config, CYAML_LOG_ERROR,
				"Load: STRING length < %"PRIu32": %s\n",
				schema->string.min, value);
		return CYAML_ERR_STRING_LENGTH_MIN;
	} else if (str_len > schema->string.max) {
		cyaml__log(ctx->config, CYAML_LOG_ERROR,
				"Load: STRING length > %"PRIu32": %s\n",
				schema->string.max, value);
		return CYAML_ERR_STRING_LENGTH_MAX;
	}



@@ 1818,7 1881,7 @@ static cyaml_err_t cyaml__set_bitval(

	switch (cyaml__get_event_type(event)) {
	case CYAML_EVT_SCALAR:
		err = cyaml__read_uint64_t(
		err = cyaml__read_uint64_t(ctx,
				(const char *)event->data.scalar.value, &value);
		if (err != CYAML_OK) {
			return err;


@@ 2206,7 2269,7 @@ static cyaml_err_t cyaml__map_key(
		cyaml_event_t cyaml_event;
		if (!(ctx->config->flags &
				CYAML_CFG_IGNORE_UNKNOWN_KEYS)) {
			cyaml__log(ctx->config, CYAML_LOG_DEBUG,
			cyaml__log(ctx->config, CYAML_LOG_ERROR,
					"Load: Unexpected key: %s\n", key);
			return CYAML_ERR_INVALID_KEY;
		}

M src/util.h => src/util.h +2 -10
@@ 15,14 15,6 @@
#include "cyaml/cyaml.h"
#include "utf8.h"

/** Compile time assertion macro. */
#define cyaml_static_assert(e) \
{ \
	enum { \
		cyaml_static_assert_check = 1 / (!!(e)) \
	}; \
}

/** Macro to squash unused variable compiler warnings. */
#define CYAML_UNUSED(_x) ((void)(_x))



@@ 37,7 29,7 @@ static inline bool cyaml__host_is_little_endian(void)
{
	static const uint16_t test = 1;

	return ((uint8_t *) &test)[0] == 1;
	return ((const uint8_t *) &test)[0] == 1;
}

/**


@@ 129,7 121,7 @@ static inline const char * cyaml__type_to_str(cyaml_type_e type)
static inline void cyaml__log(
		const cyaml_config_t *cfg,
		cyaml_log_t level,
		char *fmt, ...)
		const char *fmt, ...)
{
	if (level >= cfg->log_level && cfg->log_fn != NULL) {
		va_list args;

M test/units/errs.c => test/units/errs.c +226 -17
@@ 12,6 12,7 @@
#include <cyaml/cyaml.h>

#include "ttest.h"
#include "test.h"

/** Macro to squash unused variable compiler warnings. */
#define UNUSED(_x) ((void)(_x))


@@ 243,10 244,11 @@ static bool test_err_load_null_mem_fn(
		.schema = NULL,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.mem_fn = NULL;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, NULL,
			(cyaml_data_t **) NULL, NULL);


@@ 294,10 296,11 @@ static bool test_err_save_null_mem_fn(
		.config = &cfg,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.mem_fn = NULL;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, &data, 0);
	if (err != CYAML_ERR_BAD_CONFIG_NULL_MEMFN) {


@@ 2445,9 2448,10 @@ static bool test_err_save_schema_invalid_value_null_ptr(
		.config = &cfg,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_STYLE_BLOCK;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, data,
			CYAML_ARRAY_LEN(data));


@@ 2881,7 2885,7 @@ static bool test_err_save_schema_bad_bitfield(
 * \param[in]  config  The CYAML config to use for the test.
 * \return true if test passes, false otherwise.
 */
static bool test_err_load_schema_invalid_value_float_range(
static bool test_err_load_schema_invalid_value_float_range1(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{


@@ 2891,7 2895,152 @@ static bool test_err_load_schema_invalid_value_float_range(
		float a;
	} *data_tgt = NULL;
	static const struct cyaml_schema_field mapping_schema[] = {
		CYAML_FIELD_FLOAT("a", CYAML_FLAG_DEFAULT,
		CYAML_FIELD_FLOAT("a",
				CYAML_FLAG_DEFAULT | CYAML_FLAG_STRICT,
				struct target_struct, a),
		CYAML_FIELD_END
	};
	static const struct cyaml_schema_value top_schema = {
		CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER,
				struct target_struct, mapping_schema),
	};
	test_data_t td = {
		.data = (cyaml_data_t **) &data_tgt,
		.config = config,
		.schema = &top_schema,
	};
	cyaml_err_t err;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);
	if (err != CYAML_ERR_INVALID_VALUE) {
		return ttest_fail(&tc, cyaml_strerror(err));
	}

	if (data_tgt != NULL) {
		return ttest_fail(&tc, "Data non-NULL on error.");
	}

	return ttest_pass(&tc);
}

/**
 * Test loading when schema expects float but value is out of range.
 *
 * \param[in]  report  The test report context.
 * \param[in]  config  The CYAML config to use for the test.
 * \return true if test passes, false otherwise.
 */
static bool test_err_load_schema_invalid_value_float_range2(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{
	static const unsigned char yaml[] =
		"a: -3.5e+38\n";
	struct target_struct {
		float a;
	} *data_tgt = NULL;
	static const struct cyaml_schema_field mapping_schema[] = {
		CYAML_FIELD_FLOAT("a",
				CYAML_FLAG_DEFAULT | CYAML_FLAG_STRICT,
				struct target_struct, a),
		CYAML_FIELD_END
	};
	static const struct cyaml_schema_value top_schema = {
		CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER,
				struct target_struct, mapping_schema),
	};
	test_data_t td = {
		.data = (cyaml_data_t **) &data_tgt,
		.config = config,
		.schema = &top_schema,
	};
	cyaml_err_t err;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);
	if (err != CYAML_ERR_INVALID_VALUE) {
		return ttest_fail(&tc, cyaml_strerror(err));
	}

	if (data_tgt != NULL) {
		return ttest_fail(&tc, "Data non-NULL on error.");
	}

	return ttest_pass(&tc);
}

/**
 * Test loading when schema expects float but value is out of range.
 *
 * \param[in]  report  The test report context.
 * \param[in]  config  The CYAML config to use for the test.
 * \return true if test passes, false otherwise.
 */
static bool test_err_load_schema_invalid_value_float_range3(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{
	static const unsigned char yaml[] =
		"a: 1.55331e-40f\n";
	struct target_struct {
		float a;
	} *data_tgt = NULL;
	static const struct cyaml_schema_field mapping_schema[] = {
		CYAML_FIELD_FLOAT("a",
				CYAML_FLAG_DEFAULT | CYAML_FLAG_STRICT,
				struct target_struct, a),
		CYAML_FIELD_END
	};
	static const struct cyaml_schema_value top_schema = {
		CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER,
				struct target_struct, mapping_schema),
	};
	test_data_t td = {
		.data = (cyaml_data_t **) &data_tgt,
		.config = config,
		.schema = &top_schema,
	};
	cyaml_err_t err;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);
	if (err != CYAML_ERR_INVALID_VALUE) {
		return ttest_fail(&tc, cyaml_strerror(err));
	}

	if (data_tgt != NULL) {
		return ttest_fail(&tc, "Data non-NULL on error.");
	}

	return ttest_pass(&tc);
}

/**
 * Test loading when schema expects float but value is out of range.
 *
 * \param[in]  report  The test report context.
 * \param[in]  config  The CYAML config to use for the test.
 * \return true if test passes, false otherwise.
 */
static bool test_err_load_schema_invalid_value_float_range4(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{
	static const unsigned char yaml[] =
		"a: -1.55331e-40f\n";
	struct target_struct {
		float a;
	} *data_tgt = NULL;
	static const struct cyaml_schema_field mapping_schema[] = {
		CYAML_FIELD_FLOAT("a",
				CYAML_FLAG_DEFAULT | CYAML_FLAG_STRICT,
				struct target_struct, a),
		CYAML_FIELD_END
	};


@@ 2975,17 3124,66 @@ static bool test_err_load_schema_invalid_value_float_invalid(
 * \param[in]  config  The CYAML config to use for the test.
 * \return true if test passes, false otherwise.
 */
static bool test_err_load_schema_invalid_value_double_range(
static bool test_err_load_schema_invalid_value_double_range1(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{
	static const unsigned char yaml[] =
		"a: 1.8e+308\n";
		"a: 1.8e+4999\n";
	struct target_struct {
		double a;
	} *data_tgt = NULL;
	static const struct cyaml_schema_field mapping_schema[] = {
		CYAML_FIELD_FLOAT("a", CYAML_FLAG_DEFAULT,
		CYAML_FIELD_FLOAT("a",
				CYAML_FLAG_DEFAULT | CYAML_FLAG_STRICT,
				struct target_struct, a),
		CYAML_FIELD_END
	};
	static const struct cyaml_schema_value top_schema = {
		CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER,
				struct target_struct, mapping_schema),
	};
	test_data_t td = {
		.data = (cyaml_data_t **) &data_tgt,
		.config = config,
		.schema = &top_schema,
	};
	cyaml_err_t err;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);
	if (err != CYAML_ERR_INVALID_VALUE) {
		return ttest_fail(&tc, cyaml_strerror(err));
	}

	if (data_tgt != NULL) {
		return ttest_fail(&tc, "Data non-NULL on error.");
	}

	return ttest_pass(&tc);
}

/**
 * Test loading when schema expects double but value is out of range.
 *
 * \param[in]  report  The test report context.
 * \param[in]  config  The CYAML config to use for the test.
 * \return true if test passes, false otherwise.
 */
static bool test_err_load_schema_invalid_value_double_range2(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{
	static const unsigned char yaml[] =
		"a: -1.8e+4999\n";
	struct target_struct {
		double a;
	} *data_tgt = NULL;
	static const struct cyaml_schema_field mapping_schema[] = {
		CYAML_FIELD_FLOAT("a",
				CYAML_FLAG_DEFAULT | CYAML_FLAG_STRICT,
				struct target_struct, a),
		CYAML_FIELD_END
	};


@@ 5310,10 5508,11 @@ static bool test_err_load_flag_value_alias(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_NO_ALIAS;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5380,10 5579,11 @@ static bool test_err_load_bitfield_value_alias_1(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_NO_ALIAS;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5450,10 5650,11 @@ static bool test_err_load_bitfield_value_alias_2(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_NO_ALIAS;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5509,10 5710,11 @@ static bool test_err_load_mapping_key_alias(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_NO_ALIAS;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5568,10 5770,11 @@ static bool test_err_load_mapping_value_alias_1(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_NO_ALIAS;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5624,10 5827,11 @@ static bool test_err_load_mapping_value_alias_2(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_NO_ALIAS | CYAML_CFG_IGNORE_UNKNOWN_KEYS;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5677,10 5881,11 @@ static bool test_err_load_mapping_value_alias_3(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_NO_ALIAS;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5898,13 6103,17 @@ bool errs_tests(
	pass &= test_err_load_schema_invalid_value_int_range_3(rc, &config);
	pass &= test_err_load_schema_invalid_value_int_range_4(rc, &config);
	pass &= test_err_load_schema_invalid_value_int_range_5(rc, &config);
	pass &= test_err_load_schema_invalid_value_float_range(rc, &config);
	pass &= test_err_load_schema_invalid_value_double_range(rc, &config);
	pass &= test_err_load_schema_invalid_value_uint_range_1(rc, &config);
	pass &= test_err_load_schema_invalid_value_uint_range_2(rc, &config);
	pass &= test_err_load_schema_invalid_value_uint_range_3(rc, &config);
	pass &= test_err_load_schema_invalid_value_uint_range_4(rc, &config);
	pass &= test_err_load_schema_invalid_value_uint_range_5(rc, &config);
	pass &= test_err_load_schema_invalid_value_float_range1(rc, &config);
	pass &= test_err_load_schema_invalid_value_float_range2(rc, &config);
	pass &= test_err_load_schema_invalid_value_float_range3(rc, &config);
	pass &= test_err_load_schema_invalid_value_float_range4(rc, &config);
	pass &= test_err_load_schema_invalid_value_double_range1(rc, &config);
	pass &= test_err_load_schema_invalid_value_double_range2(rc, &config);
	pass &= test_err_load_schema_invalid_value_float_invalid(rc, &config);
	pass &= test_err_load_schema_invalid_value_double_invalid(rc, &config);


M test/units/file.c => test/units/file.c +1 -0
@@ 11,6 11,7 @@
#include <cyaml/cyaml.h>

#include "ttest.h"
#include "test.h"

/**
 * Unit test context data.

M test/units/free.c => test/units/free.c +1 -0
@@ 11,6 11,7 @@
#include <cyaml/cyaml.h>

#include "ttest.h"
#include "test.h"

/** Macro to squash unused variable compiler warnings. */
#define UNUSED(_x) ((void)(_x))

M test/units/load.c => test/units/load.c +241 -14
@@ 13,6 13,7 @@

#include "../../src/data.h"
#include "ttest.h"
#include "test.h"

/** Macro to squash unused variable compiler warnings. */
#define UNUSED(_x) ((void)(_x))


@@ 388,6 389,56 @@ static bool test_load_mapping_entry_float(
}

/**
 * Test loading a floating point value as a float.
 *
 * \param[in]  report  The test report context.
 * \param[in]  config  The CYAML config to use for the test.
 * \return true if test passes, false otherwise.
 */
static bool test_load_mapping_entry_float_underflow(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{
	float value = 1.55331e-40f;
	static const unsigned char yaml[] =
		"test_fp: 1.55331e-40\n";
	struct target_struct {
		float test_value_fp;
	} *data_tgt = NULL;
	static const struct cyaml_schema_field mapping_schema[] = {
		CYAML_FIELD_FLOAT("test_fp", CYAML_FLAG_DEFAULT,
				struct target_struct, test_value_fp),
		CYAML_FIELD_END
	};
	static const struct cyaml_schema_value top_schema = {
		CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER,
				struct target_struct, mapping_schema),
	};
	test_data_t td = {
		.data = (cyaml_data_t **) &data_tgt,
		.config = config,
		.schema = &top_schema,
	};
	cyaml_err_t err;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);
	if (err != CYAML_OK) {
		return ttest_fail(&tc, cyaml_strerror(err));
	}

	if (data_tgt->test_value_fp != value) {
		return ttest_fail(&tc, "Incorrect value: "
				"expected: %e, got: %e",
				value, data_tgt->test_value_fp);
	}

	return ttest_pass(&tc);
}

/**
 * Test loading a floating point value as a pointer to float.
 *
 * \param[in]  report  The test report context.


@@ 488,6 539,57 @@ static bool test_load_mapping_entry_double(
}

/**
 * Test loading a floating point value as a double.
 *
 * \param[in]  report  The test report context.
 * \param[in]  config  The CYAML config to use for the test.
 * \return true if test passes, false otherwise.
 */
static bool test_load_mapping_entry_double_underflow(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{
	double value = 1.79769e+308;
	static const unsigned char yaml[] =
		"test_fp: 1.79769e+309\n";
	struct target_struct {
		double test_value_fp;
	} *data_tgt = NULL;
	static const struct cyaml_schema_field mapping_schema[] = {
		CYAML_FIELD_FLOAT("test_fp", CYAML_FLAG_DEFAULT,
				struct target_struct, test_value_fp),
		CYAML_FIELD_END
	};
	static const struct cyaml_schema_value top_schema = {
		CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER,
				struct target_struct, mapping_schema),
	};
	test_data_t td = {
		.data = (cyaml_data_t **) &data_tgt,
		.config = config,
		.schema = &top_schema,
	};
	cyaml_err_t err;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	value *= 10;
	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);
	if (err != CYAML_OK) {
		return ttest_fail(&tc, cyaml_strerror(err));
	}

	if (data_tgt->test_value_fp != value) {
		return ttest_fail(&tc, "Incorrect value: "
				"expected: %lf, got: %lf",
				value, data_tgt->test_value_fp);
	}

	return ttest_pass(&tc);
}

/**
 * Test loading a floating point value as a pointer to double.
 *
 * \param[in]  report  The test report context.


@@ 908,6 1010,66 @@ static bool test_load_mapping_entry_enum_sparse(
}

/**
 * Test loading an enumeration with numerical fallback.
 *
 * \param[in]  report  The test report context.
 * \param[in]  config  The CYAML config to use for the test.
 * \return true if test passes, false otherwise.
 */
static bool test_load_mapping_entry_enum_fallback(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{
	enum test_enum {
		TEST_ENUM_FIRST  = 3,
		TEST_ENUM_SECOND = 77,
		TEST_ENUM_THIRD  = 183,
		TEST_ENUM_FOURTH = 9900,
	} value = TEST_ENUM_SECOND;
	static const cyaml_strval_t strings[] = {
		{ "first",  TEST_ENUM_FIRST },
		{ "second", TEST_ENUM_SECOND },
		{ "third",  TEST_ENUM_THIRD },
		{ "fourth", TEST_ENUM_FOURTH },
	};
	static const unsigned char yaml[] =
		"test_enum: 77\n";
	struct target_struct {
		enum test_enum test_value_enum;
	} *data_tgt = NULL;
	static const struct cyaml_schema_field mapping_schema[] = {
		CYAML_FIELD_ENUM("test_enum", CYAML_FLAG_DEFAULT,
				struct target_struct, test_value_enum,
				strings, CYAML_ARRAY_LEN(strings)),
		CYAML_FIELD_END
	};
	static const struct cyaml_schema_value top_schema = {
		CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER,
				struct target_struct, mapping_schema),
	};
	test_data_t td = {
		.data = (cyaml_data_t **) &data_tgt,
		.config = config,
		.schema = &top_schema,
	};
	cyaml_err_t err;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);
	if (err != CYAML_OK) {
		return ttest_fail(&tc, cyaml_strerror(err));
	}

	if (data_tgt->test_value_enum != value) {
		return ttest_fail(&tc, "Incorrect value");
	}

	return ttest_pass(&tc);
}

/**
 * Test loading a string to a character array.
 *
 * \param[in]  report  The test report context.


@@ 1707,12 1869,13 @@ static bool test_load_mapping_entry_mapping(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	memset(&value, 0, sizeof(value));
	value.a = 123;
	value.b = 9999;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 1770,12 1933,13 @@ static bool test_load_mapping_entry_mapping_ptr(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	memset(&value, 0, sizeof(value));
	value.a = 123;
	value.b = 9999;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 2350,6 2514,7 @@ static bool test_load_mapping_entry_sequence_mapping(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	memset(ref, 0, sizeof(ref));
	ref[0].a = 123;


@@ 2359,7 2524,7 @@ static bool test_load_mapping_entry_sequence_mapping(
	ref[2].a = 1;
	ref[2].b = 765;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 4865,7 5030,7 @@ static bool test_load_mapping_with_optional_fields(
		const cyaml_config_t *config)
{
	long values[] = { 4, 3, 2, 1 };
	struct target_struct {
	const struct target_struct {
		char *a;
		char b[10];
		int c;


@@ 4880,12 5045,12 @@ static bool test_load_mapping_with_optional_fields(
		long *k;
		unsigned k_count;
	} data = {
		.a = "Hello",
		.a = (char *) "Hello",
		.b = "World!",
		.c = 0,
		.d = { 0, 0, 0, 0 },
		.e = values,
		.f = "Required!",
		.f = (char *) "Required!",
		.g = NULL,
		.h = "\0",
		.i = 9876,


@@ 5057,6 5222,56 @@ static bool test_load_mapping_only_optional_fields(
}

/**
 * Test loading a mapping with only optional fields.
 *
 * \param[in]  report  The test report context.
 * \param[in]  config  The CYAML config to use for the test.
 * \return true if test passes, false otherwise.
 */
static bool test_load_mapping_without_any_fields(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{
	struct target_struct {
		int i;
	};
	static const unsigned char yaml[] =
		"{}\n";
	struct target_struct *data_tgt = NULL;
	static const struct cyaml_schema_field mapping_schema[] = {
		CYAML_FIELD_END
	};
	static const struct cyaml_schema_value top_schema = {
		CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER,
				struct target_struct, mapping_schema),
	};
	test_data_t td = {
		.data = (cyaml_data_t **) &data_tgt,
		.config = config,
		.schema = &top_schema,
	};
	cyaml_err_t err;

	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);
	if (err != CYAML_OK) {
		return ttest_fail(&tc, cyaml_strerror(err));
	}

	if (data_tgt == NULL) {
		return ttest_fail(&tc, "Should have allocated empty structure");
	}

	if (data_tgt->i != 0) {
		return ttest_fail(&tc, "Value should be initialied to 0");
	}

	return ttest_pass(&tc);
}

/**
 * Test loading a mapping with unknown keys ignored by config.
 *
 * \param[in]  report  The test report context.


@@ 5246,9 5461,10 @@ static bool test_load_no_log(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.log_fn = NULL;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5430,9 5646,10 @@ static bool test_load_enum_insensitive(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_CASE_INSENSITIVE;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5483,9 5700,10 @@ static bool test_load_flags_insensitive(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_CASE_INSENSITIVE;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5555,9 5773,10 @@ static bool test_load_mapping_fields_cfg_insensitive_1(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_CASE_INSENSITIVE;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5639,9 5858,10 @@ static bool test_load_mapping_fields_cfg_insensitive_2(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_CASE_INSENSITIVE;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5723,9 5943,10 @@ static bool test_load_mapping_fields_cfg_insensitive_3(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_CASE_INSENSITIVE;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5808,9 6029,10 @@ static bool test_load_mapping_fields_value_sensitive_1(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_CASE_INSENSITIVE;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 5894,9 6116,10 @@ static bool test_load_mapping_fields_value_insensitive_1(
		.schema = &top_schema,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_CASE_INSENSITIVE;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema,
			(cyaml_data_t **) &data_tgt, NULL);


@@ 6569,8 6792,11 @@ bool load_tests(
	pass &= test_load_mapping_entry_enum_sparse(rc, &config);
	pass &= test_load_mapping_entry_ignore_deep(rc, &config);
	pass &= test_load_mapping_entry_ignore_scalar(rc, &config);
	pass &= test_load_mapping_entry_enum_fallback(rc, &config);
	pass &= test_load_mapping_entry_bool_true_ptr(rc, &config);
	pass &= test_load_mapping_entry_bool_false_ptr(rc, &config);
	pass &= test_load_mapping_entry_float_underflow(rc, &config);
	pass &= test_load_mapping_entry_double_underflow(rc, &config);
	pass &= test_load_mapping_entry_string_ptr_empty(rc, &config);
	pass &= test_load_mapping_entry_string_ptr_null_str(rc, &config);
	pass &= test_load_mapping_entry_string_ptr_null_empty(rc, &config);


@@ 6642,6 6868,7 @@ bool load_tests(
	pass &= test_load_schema_top_level_string(rc, &config);
	pass &= test_load_schema_top_level_sequence(rc, &config);
	pass &= test_load_multiple_documents_ignored(rc, &config);
	pass &= test_load_mapping_without_any_fields(rc, &config);
	pass &= test_load_mapping_with_multiple_fields(rc, &config);
	pass &= test_load_mapping_with_optional_fields(rc, &config);
	pass &= test_load_mapping_only_optional_fields(rc, &config);

M test/units/save.c => test/units/save.c +36 -17
@@ 13,6 13,7 @@

#include "../../src/data.h"
#include "ttest.h"
#include "test.h"

/** Macro to squash unused variable compiler warnings. */
#define UNUSED(_x) ((void)(_x))


@@ 1698,11 1699,12 @@ static bool test_save_mapping_entry_sequence_string(
		uint32_t seq_count;
	} data = {
		.seq = {
			"This",
			"is",
			"merely",
			"a",
			"test", },
			{ 'T', 'h', 'i', 's'},
			{ 'i', 's', },
			{ 'm', 'e', 'r', 'e', 'l', 'y', },
			{ 'a', },
			{ 't', 'e', 's', 't', },
		},
		.seq_count = CYAML_ARRAY_LEN(data.seq),
	};
	static const struct cyaml_schema_value entry_schema = {


@@ 1770,11 1772,11 @@ static bool test_save_mapping_entry_sequence_string_ptr(
		uint32_t seq_count;
	} data = {
		.seq = {
			"This",
			"is",
			"merely",
			"a",
			"test", },
			(char *) "This",
			(char *) "is",
			(char *) "merely",
			(char *) "a",
			(char *) "test", },
		.seq_count = CYAML_ARRAY_LEN(data.seq),
	};
	static const struct cyaml_schema_value entry_schema = {


@@ 3476,7 3478,7 @@ static bool test_save_sequence_null_values_int(
		ttest_report_ctx_t *report,
		const cyaml_config_t *config)
{
	static const unsigned char ref[] =
	static const unsigned char ref1[] =
		"---\n"
		"- 7\n"
		"- 6\n"


@@ 3487,6 3489,18 @@ static bool test_save_sequence_null_values_int(
		"- \n"
		"- 0\n"
		"...\n";
	/* As of libyaml 0.2.5, trailing spaces are not emitted. */
	static const unsigned char ref2[] =
		"---\n"
		"- 7\n"
		"- 6\n"
		"- 5\n"
		"-\n"
		"- 3\n"
		"- 2\n"
		"-\n"
		"- 0\n"
		"...\n";
	static const int d[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
	static const int *data[] = { d + 0, d + 1, d + 2, NULL,
	                             d + 4, d + 5, NULL, d + 7, };


@@ 3505,9 3519,10 @@ static bool test_save_sequence_null_values_int(
		.config = &cfg,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_STYLE_BLOCK;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, data,
			CYAML_ARRAY_LEN(data));


@@ 3515,11 3530,12 @@ static bool test_save_sequence_null_values_int(
		return ttest_fail(&tc, cyaml_strerror(err));
	}

	if (len != YAML_LEN(ref) || memcmp(ref, buffer, len) != 0) {
	if ((len != YAML_LEN(ref1) || memcmp(ref1, buffer, len) != 0) &&
	    (len != YAML_LEN(ref2) || memcmp(ref2, buffer, len) != 0)) {
		return ttest_fail(&tc, "Bad data:\n"
				"EXPECTED (%zu):\n\n%.*s\n\n"
				"GOT (%zu):\n\n%.*s\n",
				YAML_LEN(ref), YAML_LEN(ref), ref,
				YAML_LEN(ref1), YAML_LEN(ref1), ref1,
				len, len, buffer);
	}



@@ 3566,9 3582,10 @@ static bool test_save_sequence_null_str_values_int(
		.config = &cfg,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_STYLE_BLOCK;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, data,
			CYAML_ARRAY_LEN(data));


@@ 3668,9 3685,10 @@ static bool test_save_sequence_config_flow_style(
		.config = &cfg,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_STYLE_FLOW;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, data, 3);
	if (err != CYAML_OK) {


@@ 3721,9 3739,10 @@ static bool test_save_sequence_config_block_style(
		.config = &cfg,
	};
	cyaml_err_t err;
	ttest_ctx_t tc;

	cfg.flags |= CYAML_CFG_STYLE_BLOCK;
	ttest_ctx_t tc = ttest_start(report, __func__, cyaml_cleanup, &td);
	tc = ttest_start(report, __func__, cyaml_cleanup, &td);

	err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, data, 3);
	if (err != CYAML_OK) {

M test/units/test.c => test/units/test.c +2 -43
@@ 13,55 13,14 @@
#include <cyaml/cyaml.h>

#include "ttest.h"

/** In load.c */
extern bool load_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In file.c */
extern bool file_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In free.c */
extern bool free_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In utf8.c */
extern bool utf8_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In util.c */
extern bool util_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In errs.c */
extern bool errs_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In save.c */
extern bool save_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);
#include "test.h"

/**
 * Print program usage
 *
 * \param[in]  prog_name  Name of program.
 */
void usage(const char *prog_name)
static void usage(const char *prog_name)
{
	fprintf(stderr, "Usage: %s [-q|-v|-d]\n", prog_name);
}

A test/units/test.h => test/units/test.h +52 -0
@@ 0,0 1,52 @@
/*
 * SPDX-License-Identifier: ISC
 *
 * Copyright (C) 2021 Michael Drake <tlsa@netsurf-browser.org>
 */

#ifndef TEST_H
#define TEST_H

/** In load.c */
extern bool load_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In file.c */
extern bool file_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In free.c */
extern bool free_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In utf8.c */
extern bool utf8_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In util.c */
extern bool util_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In errs.c */
extern bool errs_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

/** In save.c */
extern bool save_tests(
		ttest_report_ctx_t *rc,
		cyaml_log_t log_level,
		cyaml_log_fn_t log_fn);

#endif

M test/units/utf8.c => test/units/utf8.c +1 -0
@@ 13,6 13,7 @@
#include "../../src/utf8.h"

#include "ttest.h"
#include "test.h"

/** Helper macro to squash unused variable warnings. */
#define UNUSED(_x) ((void)(_x))

M test/units/util.c => test/units/util.c +1 -0
@@ 15,6 15,7 @@
#include "../../src/util.h"

#include "ttest.h"
#include "test.h"

/**
 * Test cyaml memory functions.