/* * SPDX-License-Identifier: ISC * * Copyright (C) 2018-2021 Michael Drake */ #include #include #include #include #include #include #include "ttest.h" #include "test.h" /** Macro to squash unused variable compiler warnings. */ #define UNUSED(_x) ((void)(_x)) /** Helper macro to count bytes of YAML input data. */ #define YAML_LEN(_y) (sizeof(_y) - 1) /** * Unit test context data. */ typedef struct test_data { char **buffer; cyaml_data_t **data; unsigned *seq_count; const struct cyaml_config *config; const struct cyaml_schema_value *schema; } test_data_t; /** * Common clean up function to free data loaded by tests. * * \param[in] data The unit test context data. */ static void cyaml_cleanup(void *data) { struct test_data *td = data; unsigned seq_count = 0; if (td->seq_count != NULL) { seq_count = *(td->seq_count); } if (td->config->mem_fn != NULL && td->buffer != NULL) { td->config->mem_fn(td->config->mem_ctx, *(td->buffer), 0); } if (td->data != NULL) { cyaml_free(td->config, td->schema, *(td->data), seq_count); } } /** * Test loading with NULL data parameter. * * \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_null_data( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = ""; struct target_struct { int value; } *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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) NULL, NULL); if (err != CYAML_ERR_BAD_PARAM_NULL_DATA) { 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 saving with NULL data parameter. * * \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_save_null_data( ttest_report_ctx_t *report, const cyaml_config_t *config) { struct target_struct { int value; } *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), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .data = (cyaml_data_t **) &data_tgt, .config = config, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, NULL, 0); if (err != CYAML_ERR_BAD_PARAM_NULL_DATA) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading with NULL config parameter. * * \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_null_config( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = ""; void *data_tgt = NULL; test_data_t td = { .data = (cyaml_data_t **) &data_tgt, .config = config, .schema = NULL, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), NULL, NULL, (cyaml_data_t **) NULL, NULL); if (err != CYAML_ERR_BAD_PARAM_NULL_CONFIG) { 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 saving with NULL config parameter. * * \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_save_null_config( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const struct target_struct { unsigned test_uint; } data = { .test_uint = 555, }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("test_uint", CYAML_FLAG_DEFAULT, struct target_struct, test_uint), CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, NULL, &top_schema, &data, 0); if (err != CYAML_ERR_BAD_PARAM_NULL_CONFIG) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading with NULL memory allocation function. * * \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_null_mem_fn( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = ""; cyaml_config_t cfg = *config; void *data_tgt = NULL; test_data_t td = { .data = (cyaml_data_t **) &data_tgt, .config = &cfg, .schema = NULL, }; cyaml_err_t err; ttest_ctx_t tc; cfg.mem_fn = NULL; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, NULL, (cyaml_data_t **) NULL, NULL); if (err != CYAML_ERR_BAD_CONFIG_NULL_MEMFN) { 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 saving with NULL memory allocation function. * * \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_save_null_mem_fn( ttest_report_ctx_t *report, const cyaml_config_t *config) { cyaml_config_t cfg = *config; static const struct target_struct { unsigned test_uint; } data = { .test_uint = 555, }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("test_uint", CYAML_FLAG_DEFAULT, struct target_struct, test_uint), CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = &cfg, }; cyaml_err_t err; ttest_ctx_t tc; cfg.mem_fn = NULL; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, &data, 0); if (err != CYAML_ERR_BAD_CONFIG_NULL_MEMFN) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading with NULL schema. * * \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_null_schema( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = ""; void *data_tgt = NULL; test_data_t td = { .data = (cyaml_data_t **) &data_tgt, .config = config, .schema = NULL, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, NULL, (cyaml_data_t **) NULL, NULL); if (err != CYAML_ERR_BAD_PARAM_NULL_SCHEMA) { 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 saving with NULL schema. * * \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_save_null_schema( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const struct target_struct { unsigned test_uint; } data = { .test_uint = 555, }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, NULL, &data, 0); if (err != CYAML_ERR_BAD_PARAM_NULL_SCHEMA) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading with schema with bad top level type (non-pointer). * * \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_top_level_non_pointer( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "7\n"; int *value = NULL; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, int) }; test_data_t td = { .data = (cyaml_data_t **) &value, .config = config, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &value, NULL); if (err != CYAML_ERR_TOP_LEVEL_NON_PTR) { return ttest_fail(&tc, cyaml_strerror(err)); } if (value != NULL) { return ttest_fail(&tc, "Data non-NULL on error."); } return ttest_pass(&tc); } /** * Test saving with schema with bad top level type (non-pointer). * * \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_save_schema_top_level_non_pointer( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const struct target_struct { unsigned test_uint; } data = { .test_uint = 555, }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, int) }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_TOP_LEVEL_NON_PTR) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading with schema with bad top level sequence and no seq_count. * * \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_top_level_sequence_no_count( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key:\n"; struct target_struct { int *value; unsigned value_count; } *data_tgt = NULL; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, int) }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_SEQUENCE(CYAML_FLAG_POINTER, int, &entry_schema, 0, CYAML_UNLIMITED), }; test_data_t td = { .data = (cyaml_data_t **) &data_tgt, .config = config, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_BAD_PARAM_SEQ_COUNT) { 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 with schema with bad top level sequence and no seq_count. * * \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_top_level_not_sequence_count( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "7\n"; int *value = NULL; unsigned count = 0; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, int) }; test_data_t td = { .data = (cyaml_data_t **) &value, .seq_count = &count, .config = config, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &value, &count); if (err != CYAML_ERR_BAD_PARAM_SEQ_COUNT) { return ttest_fail(&tc, cyaml_strerror(err)); } if (value != NULL) { return ttest_fail(&tc, "Data non-NULL on error."); } return ttest_pass(&tc); } /** * Test saving with schema with a non-sequence and non-zero sequence count. * * \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_save_schema_top_level_not_sequence_count( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const struct target_struct { unsigned *test_uint; } data = { .test_uint = NULL, }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_INT(CYAML_FLAG_POINTER, int) }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 42); if (err != CYAML_ERR_BAD_PARAM_SEQ_COUNT) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading with schema with bad type. * * \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_bad_type( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key:\n"; struct target_struct { int value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = 99999, .flags = CYAML_FLAG_DEFAULT, .data_size = sizeof(data_tgt->value), }, .data_offset = offsetof(struct target_struct, value), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_BAD_TYPE_IN_SCHEMA) { 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 saving with schema with bad type. * * \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_save_schema_bad_type( ttest_report_ctx_t *report, const cyaml_config_t *config) { struct target_struct { int value; } data = { .value = 99, }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = 99999, .flags = CYAML_FLAG_DEFAULT, .data_size = sizeof(data.value), }, .data_offset = offsetof(struct target_struct, value), }, CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_BAD_TYPE_IN_SCHEMA) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading with schema with string min greater than max. * * \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_string_min_max( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "value: foo\n"; struct target_struct { const char *value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_STRING_PTR("value", CYAML_FLAG_POINTER, struct target_struct, value, 10, 9), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_BAD_MIN_MAX_SCHEMA) { return ttest_fail(&tc, cyaml_strerror(err)); } if (data_tgt != NULL) { return ttest_fail(&tc, "Data non-NULL on error."); } return ttest_pass(&tc); } /** * Only scalar mapping keys are allowed by libcyaml. * * \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_non_scalar_mapping_key( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "{1}: value"; struct target_struct { unsigned value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("key", CYAML_FLAG_DEFAULT, struct target_struct, value), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INTERNAL_ERROR) { 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 with schema with data size (0). * * \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_bad_data_size_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key: 1\n"; struct target_struct { int value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_INT, .flags = CYAML_FLAG_DEFAULT, .data_size = 0, }, .data_offset = offsetof(struct target_struct, value), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_DATA_SIZE) { 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 with schema with data size (9). * * \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_bad_data_size_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key: 1\n"; struct target_struct { int value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_INT, .flags = CYAML_FLAG_DEFAULT, .data_size = 9, }, .data_offset = offsetof(struct target_struct, value), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_DATA_SIZE) { 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 with schema with data size (0) for flags. * * \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_bad_data_size_3( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_strval_t strings[] = { { "foo", 0 }, { "bar", 1 }, { "baz", 2 }, { "bat", 3 }, }; static const unsigned char yaml[] = "key:\n" " - bat\n" " - bar\n"; struct target_struct { int value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_FLAGS, .flags = CYAML_FLAG_DEFAULT, .data_size = 0, .enumeration = { .strings = strings, .count = CYAML_ARRAY_LEN(strings), }, }, .data_offset = offsetof(struct target_struct, value), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_DATA_SIZE) { 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 with schema with data size (0) for sequence count. * * \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_bad_data_size_4( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key:\n" " - 2\n" " - 4\n"; struct target_struct { int *value; unsigned value_count; } *data_tgt = NULL; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, int), }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_SEQUENCE, .flags = CYAML_FLAG_POINTER, .data_size = sizeof(*(data_tgt->value)), .sequence = { .min = 0, .max = CYAML_UNLIMITED, .entry = &entry_schema, }, }, .data_offset = offsetof(struct target_struct, value), .count_size = 0, .count_offset = offsetof( struct target_struct, value_count), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_DATA_SIZE) { 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 with schema with data size (9) for sequence count. * * \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_bad_data_size_5( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key:\n" " - 2\n" " - 4\n"; struct target_struct { int *value; unsigned value_count; } *data_tgt = NULL; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, int), }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_SEQUENCE, .flags = CYAML_FLAG_POINTER, .data_size = sizeof(*(data_tgt->value)), .sequence = { .min = 0, .max = CYAML_UNLIMITED, .entry = &entry_schema, }, }, .data_offset = offsetof(struct target_struct, value), .count_size = 9, .count_offset = offsetof( struct target_struct, value_count), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_DATA_SIZE) { 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 with schema with data size (9) for sequence count. * * \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_bad_data_size_6( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key:\n" " - 2\n" " - 4\n"; struct target_struct { int value[4]; unsigned value_count; } *data_tgt = NULL; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, int), }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_SEQUENCE, .flags = CYAML_FLAG_DEFAULT, .data_size = sizeof(*(data_tgt->value)), .sequence = { .min = 0, .max = 4, .entry = &entry_schema, }, }, .data_offset = offsetof(struct target_struct, value), .count_size = 9, .count_offset = offsetof( struct target_struct, value_count), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_DATA_SIZE) { 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 with schema with data size (0). * * \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_bad_data_size_7( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key: 1\n"; struct target_struct { unsigned value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_UINT, .flags = CYAML_FLAG_DEFAULT, .data_size = 0, }, .data_offset = offsetof(struct target_struct, value), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_DATA_SIZE) { 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 with schema with data size (9) for bitfield. * * \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_bad_data_size_8( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_bitdef_t bitvals[] = { { .name = "a", .offset = 0, .bits = 3 }, { .name = "b", .offset = 3, .bits = 7 }, { .name = "c", .offset = 10, .bits = 32 }, { .name = "d", .offset = 42, .bits = 8 }, { .name = "e", .offset = 50, .bits = 14 }, }; static const unsigned char yaml[] = "test_bitfield:\n" " a: 0x7\n" " b: 0x7f\n" " c: 0xffffffff\n" " d: 0xff\n" " e: 0x3fff\n"; struct target_struct { uint64_t value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { { .key = "test_bitfield", .value = { .type = CYAML_BITFIELD, .flags = CYAML_FLAG_DEFAULT, .data_size = 9, .bitfield = { .bitdefs = bitvals, .count = CYAML_ARRAY_LEN(bitvals), }, }, .data_offset = offsetof(struct target_struct, value), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_DATA_SIZE) { 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 with schema with data size (9) for flags. * * \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_bad_data_size_9( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_strval_t strings[] = { { "foo", 0 }, { "bar", 1 }, { "baz", 2 }, { "bat", 3 }, }; static const unsigned char yaml[] = "key:\n" " - bat\n" " - bar\n"; struct target_struct { int value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_FLAGS, .flags = CYAML_FLAG_DEFAULT, .data_size = 9, .enumeration = { .strings = strings, .count = CYAML_ARRAY_LEN(strings), }, }, .data_offset = offsetof(struct target_struct, value), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_DATA_SIZE) { 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 saving with schema with data size (0). * * \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_save_schema_bad_data_size_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const struct target_struct { int value; } data = { .value = 9, }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_INT, .flags = CYAML_FLAG_DEFAULT, .data_size = 0, }, .data_offset = offsetof(struct target_struct, value), }, CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_INVALID_DATA_SIZE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test saving with schema with data size (0). * * \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_save_schema_bad_data_size_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const struct target_struct { unsigned value; } data = { .value = 9, }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_UINT, .flags = CYAML_FLAG_DEFAULT, .data_size = 0, }, .data_offset = offsetof(struct target_struct, value), }, CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_INVALID_DATA_SIZE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test saving with schema with data size (0). * * \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_save_schema_bad_data_size_3( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const struct target_struct { bool value; } data = { .value = 1, }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_BOOL, .flags = CYAML_FLAG_DEFAULT, .data_size = 0, }, .data_offset = offsetof(struct target_struct, value), }, CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_INVALID_DATA_SIZE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test saving with schema with data size (0). * * \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_save_schema_bad_data_size_4( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_e { FIRST, SECOND, THIRD, FOURTH, COUNT }; static const cyaml_strval_t strings[COUNT] = { [FIRST] = { "first", 0 }, [SECOND] = { "second", 1 }, [THIRD] = { "third", 2 }, [FOURTH] = { "fourth", 3 }, }; static const struct target_struct { enum test_e value; } data = { .value = 1, }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_ENUM, .flags = CYAML_FLAG_DEFAULT, .data_size = 0, .enumeration = { .strings = strings, .count = COUNT, }, }, .data_offset = offsetof(struct target_struct, value), }, CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_INVALID_DATA_SIZE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test saving with schema with data size (5 for floating point value). * * \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_save_schema_bad_data_size_5( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const struct target_struct { float value; } data = { .value = 3.14f, }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_FLOAT, .flags = CYAML_FLAG_DEFAULT, .data_size = 5, }, .data_offset = offsetof(struct target_struct, value), }, CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_INVALID_DATA_SIZE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test saving with schema with data size (0). * * \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_save_schema_bad_data_size_6( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_f { NONE = 0, FIRST = (1 << 0), SECOND = (1 << 1), THIRD = (1 << 2), FOURTH = (1 << 3), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, }; static const struct target_struct { enum test_f value; } data = { .value = THIRD, }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_FLAGS, .flags = CYAML_FLAG_DEFAULT, .data_size = 0, .enumeration = { .strings = strings, .count = 4, }, }, .data_offset = offsetof(struct target_struct, value), }, CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_INVALID_DATA_SIZE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test saving with schema with a bad sequence count size. * * \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_save_schema_bad_data_size_7( ttest_report_ctx_t *report, const cyaml_config_t *config) { struct target_struct { unsigned *seq; uint32_t seq_count; } data = { .seq = NULL, }; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_UINT(CYAML_FLAG_DEFAULT, *(data.seq)), }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "sequence", .value = { .type = CYAML_SEQUENCE, .flags = CYAML_FLAG_POINTER, .data_size = sizeof(*(data.seq)), .sequence = { .entry = &entry_schema, .min = 0, .max = 10, }, }, .data_offset = offsetof(struct target_struct, seq), .count_offset = offsetof(struct target_struct, seq_count), .count_size = 9, }, CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_INVALID_DATA_SIZE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test saving with schema with data size (0). * * \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_save_schema_bad_data_size_8( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_bitdef_t bitvals[] = { { .name = "a", .offset = 0, .bits = 3 }, { .name = "b", .offset = 3, .bits = 7 }, { .name = "c", .offset = 10, .bits = 32 }, { .name = "d", .offset = 42, .bits = 8 }, { .name = "e", .offset = 50, .bits = 14 }, }; static const struct target_struct { uint64_t test_bitfield; } data = { .test_bitfield = 0xFFFFFFFFFFFFFFFFu, }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "test_bitfield", .value = { .type = CYAML_BITFIELD, .flags = CYAML_FLAG_DEFAULT, .data_size = 0, .bitfield = { .bitdefs = bitvals, .count = CYAML_ARRAY_LEN(bitvals), }, }, .data_offset = offsetof(struct target_struct, test_bitfield), }, CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_INVALID_DATA_SIZE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading with schema with sequence fixed with unequal min and max. * * \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_sequence_min_max( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "sequence:\n" " - \n"; struct target_struct { unsigned *seq; uint32_t seq_count; } *data_tgt = NULL; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_UINT(CYAML_FLAG_DEFAULT, *(data_tgt->seq)), }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "sequence", .value = { .type = CYAML_SEQUENCE_FIXED, .flags = CYAML_FLAG_POINTER, .data_size = sizeof(*(data_tgt->seq)), .sequence = { .entry = &entry_schema, .min = 0, .max = CYAML_UNLIMITED, }, }, .data_offset = offsetof(struct target_struct, seq), .count_offset = offsetof(struct target_struct, seq_count), .count_size = sizeof(data_tgt->seq_count), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_SEQUENCE_FIXED_COUNT) { 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 saving with schema with sequence fixed with unequal min and max. * * \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_save_schema_sequence_min_max( ttest_report_ctx_t *report, const cyaml_config_t *config) { unsigned value = 5; struct target_struct { unsigned *seq; } data = { .seq = &value, }; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_UINT(CYAML_FLAG_DEFAULT, *(data.seq)), }; static const struct cyaml_schema_field mapping_schema[] = { { .key = "sequence", .value = { .type = CYAML_SEQUENCE_FIXED, .flags = CYAML_FLAG_POINTER, .data_size = sizeof(*(data.seq)), .sequence = { .entry = &entry_schema, .min = 0, .max = CYAML_UNLIMITED, }, }, .data_offset = offsetof(struct target_struct, seq), }, CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_SEQUENCE_FIXED_COUNT) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading with schema with data size for 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_err_load_schema_bad_data_size_float( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key: 1\n"; struct target_struct { int value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { { .key = "key", .value = { .type = CYAML_FLOAT, .flags = CYAML_FLAG_DEFAULT, .data_size = 7, }, .data_offset = offsetof(struct target_struct, value), }, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_DATA_SIZE) { 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 with schema with sequence in sequence. * * \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_sequence_in_sequence( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "- -\n"; unsigned **seq = NULL; unsigned count = 0; static const struct cyaml_schema_value inner_entry_schema = { CYAML_VALUE_UINT(CYAML_FLAG_DEFAULT, **seq), }; static const struct cyaml_schema_value outer_entry_schema = { CYAML_VALUE_SEQUENCE(CYAML_FLAG_POINTER, unsigned, &inner_entry_schema, 0, CYAML_UNLIMITED) }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_SEQUENCE(CYAML_FLAG_POINTER, unsigned *, &outer_entry_schema, 0, CYAML_UNLIMITED) }; test_data_t td = { .data = (cyaml_data_t **) &seq, .seq_count = &count, .config = config, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &seq, &count); if (err != CYAML_ERR_SEQUENCE_IN_SEQUENCE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (seq != NULL) { return ttest_fail(&tc, "Data non-NULL on error."); } return ttest_pass(&tc); } /** * Test saving with schema with sequence in sequence. * * \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_save_schema_sequence_in_sequence( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned seq[4] = { 1, 2, 3 }; static const unsigned *data[] = { seq, seq }; static const struct cyaml_schema_value inner_entry_schema = { CYAML_VALUE_UINT(CYAML_FLAG_DEFAULT, **data), }; static const struct cyaml_schema_value outer_entry_schema = { CYAML_VALUE_SEQUENCE(CYAML_FLAG_POINTER, unsigned, &inner_entry_schema, 0, CYAML_UNLIMITED) }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_SEQUENCE(CYAML_FLAG_POINTER, unsigned *, &outer_entry_schema, 0, CYAML_UNLIMITED) }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 2); if (err != CYAML_ERR_SEQUENCE_IN_SEQUENCE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading when schema expects uint, but value is invalid. * * \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_uint( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: scalar\n"; struct target_struct { unsigned a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 with schema with string top level type, with bad value. * * \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_string( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "{ Hello }\n"; char *value = NULL; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_STRING(CYAML_FLAG_POINTER, int, 0, CYAML_UNLIMITED) }; test_data_t td = { .data = (cyaml_data_t **) &value, .config = config, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &value, NULL); if (err != CYAML_ERR_INVALID_VALUE) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading when flags expected, but numerical value has trailing junk. * * \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_flags_junk( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_flags { TEST_FLAGS_NONE = 0, TEST_FLAGS_FIRST = (1 << 0), TEST_FLAGS_SECOND = (1 << 1), TEST_FLAGS_THIRD = (1 << 2), TEST_FLAGS_FOURTH = (1 << 3), TEST_FLAGS_FIFTH = (1 << 4), TEST_FLAGS_SIXTH = (1 << 5), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, { "fifth", (1 << 4) }, { "sixth", (1 << 5) }, }; static const unsigned char yaml[] = "key:\n" " - first\n" " - 1thousand\n"; struct target_struct { enum test_flags a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLAGS("key", CYAML_FLAG_DEFAULT, struct target_struct, a, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 flags, but numerical value is invalid. * * \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_flags_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_flags { TEST_FLAGS_NONE = 0, TEST_FLAGS_FIRST = (1 << 0), TEST_FLAGS_SECOND = (1 << 1), TEST_FLAGS_THIRD = (1 << 2), TEST_FLAGS_FOURTH = (1 << 3), TEST_FLAGS_FIFTH = (1 << 4), TEST_FLAGS_SIXTH = (1 << 5), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, { "fifth", (1 << 4) }, { "sixth", (1 << 5) }, }; static const unsigned char yaml[] = "key:\n" " - first\n" " - -7\n"; struct target_struct { enum test_flags a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLAGS("key", CYAML_FLAG_DEFAULT, struct target_struct, a, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 flags, but numerical value is invalid. * * \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_flags_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_flags { TEST_FLAGS_NONE = 0, TEST_FLAGS_FIRST = (1 << 0), TEST_FLAGS_SECOND = (1 << 1), TEST_FLAGS_THIRD = (1 << 2), TEST_FLAGS_FOURTH = (1 << 3), TEST_FLAGS_FIFTH = (1 << 4), TEST_FLAGS_SIXTH = (1 << 5), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, { "fifth", (1 << 4) }, { "sixth", (1 << 5) }, }; static const unsigned char yaml[] = "key:\n" " - first\n" " - 0x100000000\n"; struct target_struct { enum test_flags a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLAGS("key", CYAML_FLAG_DEFAULT, struct target_struct, a, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 flags, but numerical value is invalid. * * \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_flags_3( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_flags { TEST_FLAGS_NONE = 0, TEST_FLAGS_FIRST = (1 << 0), TEST_FLAGS_SECOND = (1 << 1), TEST_FLAGS_THIRD = (1 << 2), TEST_FLAGS_FOURTH = (1 << 3), TEST_FLAGS_FIFTH = (1 << 4), TEST_FLAGS_SIXTH = (1 << 5), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, { "fifth", (1 << 4) }, { "sixth", (1 << 5) }, }; static const unsigned char yaml[] = "key:\n" " - first\n" " - 0x10000000000000000\n"; struct target_struct { enum test_flags a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLAGS("key", CYAML_FLAG_DEFAULT, struct target_struct, a, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 saving a NULL when NULLs aren't allowed by the schema. * * \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_save_schema_invalid_value_null_ptr( ttest_report_ctx_t *report, const cyaml_config_t *config) { 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, d + 6, d + 7, }; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_POINTER, int) }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_SEQUENCE(CYAML_FLAG_POINTER, int, &entry_schema, 0, 3), }; char *buffer = NULL; size_t len = 0; cyaml_config_t cfg = *config; test_data_t td = { .buffer = &buffer, .config = &cfg, }; cyaml_err_t err; ttest_ctx_t tc; cfg.flags |= CYAML_CFG_STYLE_BLOCK; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, data, CYAML_ARRAY_LEN(data)); if (err != CYAML_ERR_INVALID_VALUE) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading when schema expects bitfield, but numerical value is invalid. * * \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_bitfield_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_bitdef_t bitvals[] = { { .name = "a", .offset = 0, .bits = 3 }, }; static const unsigned char yaml[] = "test_bitfield:\n" " a: invalid\n"; struct target_struct { uint64_t test_value_bitfield; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_BITFIELD("test_bitfield", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield, bitvals, CYAML_ARRAY_LEN(bitvals)), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 bitfield, but value is non-scalar. * * \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_bitfield_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_bitdef_t bitvals[] = { { .name = "a", .offset = 0, .bits = 3 }, }; static const unsigned char yaml[] = "test_bitfield:\n" " a: {}\n"; struct target_struct { uint64_t test_value_bitfield; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_BITFIELD("test_bitfield", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield, bitvals, CYAML_ARRAY_LEN(bitvals)), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_UNEXPECTED_EVENT) { 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 bitfield, but value is not in schema. * * \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_bitfield_3( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_bitdef_t bitvals[] = { { .name = "a", .offset = 0, .bits = 3 }, }; static const unsigned char yaml[] = "test_bitfield:\n" " b: {}\n"; struct target_struct { uint64_t test_value_bitfield; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_BITFIELD("test_bitfield", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield, bitvals, CYAML_ARRAY_LEN(bitvals)), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 bitfield, but value too big. * * \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_bitfield_4( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_bitdef_t bitvals[] = { { .name = "a", .offset = 0, .bits = 3 }, }; static const unsigned char yaml[] = "test_bitfield:\n" " a: 0xf\n"; struct target_struct { uint64_t test_value_bitfield; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_BITFIELD("test_bitfield", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield, bitvals, CYAML_ARRAY_LEN(bitvals)), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 bitfield, but value is of wrong type. * * \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_bitfield_5( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_bitdef_t bitvals[] = { { .name = "a", .offset = 0, .bits = 3 }, }; static const unsigned char yaml[] = "test_bitfield:\n" " {}: {}\n"; struct target_struct { uint64_t test_value_bitfield; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_BITFIELD("test_bitfield", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield, bitvals, CYAML_ARRAY_LEN(bitvals)), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_UNEXPECTED_EVENT) { 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 bitfield, but value is of wrong type. * * \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_bitfield_6( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_bitdef_t bitvals[] = { { .name = "a", .offset = 0, .bits = 3 }, }; static const unsigned char yaml[] = "test_bitfield:\n" " []\n"; struct target_struct { uint64_t test_value_bitfield; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_BITFIELD("test_bitfield", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield, bitvals, CYAML_ARRAY_LEN(bitvals)), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 bitfield, but value outside data. * * \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_bad_bitfield( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_bitdef_t bitvals[] = { { .name = "a", .offset = 62, .bits = 4 }, }; static const unsigned char yaml[] = "test_bitfield:\n" " a: 1\n"; struct target_struct { uint64_t test_value_bitfield; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_BITFIELD("test_bitfield", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield, bitvals, CYAML_ARRAY_LEN(bitvals)), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_BAD_BITVAL_IN_SCHEMA) { 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 saving when schema has bitfield defined outside value data. * * \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_save_schema_bad_bitfield( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_bitdef_t bitvals[] = { { .name = "a", .offset = 30, .bits = 4 }, }; static const struct target_struct { uint32_t test_bitfield; } data = { .test_bitfield = 0xFFFFFFFFu, }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_BITFIELD("test_bitfield", CYAML_FLAG_DEFAULT, struct target_struct, test_bitfield, bitvals, CYAML_ARRAY_LEN(bitvals)), CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_BAD_BITVAL_IN_SCHEMA) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } 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_range1( 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 }; 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 invalid. * * \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_junk( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 0.452*00E003\n"; struct target_struct { float a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLOAT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 invalid. * * \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_invalid( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: Gasp\n"; struct target_struct { float a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLOAT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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_range1( 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 }; 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 }; 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 invalid. * * \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_junk( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 0.452*00E003\n"; struct target_struct { double a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLOAT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 invalid. * * \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_invalid( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: Gasp\n"; struct target_struct { double a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLOAT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 int but value has trailing junk. * * \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_int_junk( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 3*9+4\n"; struct target_struct { int a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 int 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_int_range_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: -129\n"; struct target_struct { signed char a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 int 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_int_range_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 128\n"; struct target_struct { signed char a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 int 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_int_range_3( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 0x10000\n"; struct target_struct { int16_t a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 int 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_int_range_4( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 0x100000000\n"; struct target_struct { int32_t a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 int 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_int_range_5( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 0x10000000000000000\n"; struct target_struct { int32_t a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 uint but value has trailing junk. * * \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_uint_junk( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 3*8+4\n"; struct target_struct { unsigned int a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 uint 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_uint_range_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: -1\n"; struct target_struct { unsigned char a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 uint 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_uint_range_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 256\n"; struct target_struct { unsigned char a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 uint 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_uint_range_3( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 0x10000\n"; struct target_struct { uint16_t a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 uint 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_uint_range_4( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 0x100000000\n"; struct target_struct { uint32_t a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 uint 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_uint_range_5( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 0x10000000000000000\n"; struct target_struct { uint32_t a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("a", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 integer limit. * * \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_int8_limit_neg( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "val: -129\n"; struct target_struct { int8_t val; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("val", CYAML_FLAG_DEFAULT, struct target_struct, val), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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)); } return ttest_pass(&tc); } /** * Test integer limit. * * \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_int8_limit_pos( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "val: 128\n"; struct target_struct { int8_t val; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("val", CYAML_FLAG_DEFAULT, struct target_struct, val), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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)); } return ttest_pass(&tc); } /** * Test integer limit. * * \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_int16_limit_neg( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "val: -32769\n"; struct target_struct { int16_t val; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("val", CYAML_FLAG_DEFAULT, struct target_struct, val), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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)); } return ttest_pass(&tc); } /** * Test integer limit. * * \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_int16_limit_pos( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "val: 32768\n"; struct target_struct { int16_t val; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("val", CYAML_FLAG_DEFAULT, struct target_struct, val), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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)); } return ttest_pass(&tc); } /** * Test integer limit. * * \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_int32_limit_neg( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "val: -2147483649\n"; struct target_struct { int32_t val; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("val", CYAML_FLAG_DEFAULT, struct target_struct, val), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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)); } return ttest_pass(&tc); } /** * Test integer limit. * * \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_int32_limit_pos( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "val: 2147483648\n"; struct target_struct { int32_t val; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("val", CYAML_FLAG_DEFAULT, struct target_struct, val), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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)); } return ttest_pass(&tc); } /** * Test integer limit. * * \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_int64_limit_neg( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "val: -9223372036854775809\n"; struct target_struct { int64_t val; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("val", CYAML_FLAG_DEFAULT, struct target_struct, val), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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)); } return ttest_pass(&tc); } /** * Test integer limit. * * \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_int64_limit_pos( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "val: 9223372036854775808\n"; struct target_struct { int64_t val; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("val", CYAML_FLAG_DEFAULT, struct target_struct, val), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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)); } return ttest_pass(&tc); } /** * Test loading when schema expects string, but it's too short. * * \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_string_min_length( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: foo\n"; struct target_struct { char *a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_STRING_PTR("a", CYAML_FLAG_DEFAULT, struct target_struct, a, 4, 4), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_STRING_LENGTH_MIN) { 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 string, but it's too long. * * \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_string_max_length( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: fifth\n"; struct target_struct { char *a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_STRING_PTR("a", CYAML_FLAG_DEFAULT, struct target_struct, a, 4, 4), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_STRING_LENGTH_MAX) { 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 a mapping with a duplicate field. * * \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_duplicate_mapping_field( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "test_uint: 9998\n" "test_uint: 9999\n"; struct target_struct { unsigned test_value_uint; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_UINT("test_uint", CYAML_FLAG_DEFAULT, struct target_struct, test_value_uint), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_UNEXPECTED_EVENT) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading when schema expects mapping field which is not present. * * \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_missing_mapping_field( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "a: 2\n"; struct target_struct { int a; int b; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("a", CYAML_FLAG_DEFAULT, struct target_struct, a), CYAML_FIELD_INT("b", CYAML_FLAG_DEFAULT, struct target_struct, b), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_MAPPING_FIELD_MISSING) { 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 disallows mapping field. * * \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_unknown_mapping_field( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "wrong_key: 2\n"; struct target_struct { int a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("key", CYAML_FLAG_DEFAULT, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_KEY) { 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 sequence, it has too few entries. * * \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_sequence_min_entries( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key:\n" " - 1\n" " - 2\n"; struct target_struct { int *a; unsigned a_count; } *data_tgt = NULL; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, *(data_tgt->a)), }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_SEQUENCE("key", CYAML_FLAG_POINTER, struct target_struct, a, &entry_schema, 3, CYAML_UNLIMITED), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_SEQUENCE_ENTRIES_MIN) { 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 sequence, it has too many entries. * * \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_sequence_max_entries( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key:\n" " - 1\n" " - 2\n" " - 3\n"; struct target_struct { int *a; unsigned a_count; } *data_tgt = NULL; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, *(data_tgt->a)), }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_SEQUENCE("key", CYAML_FLAG_POINTER, struct target_struct, a, &entry_schema, 2, 2), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_SEQUENCE_ENTRIES_MAX) { 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 flags and finds a mapping inside. * * \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_flags_mapping( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_flags { TEST_FLAGS_NONE = 0, TEST_FLAGS_FIRST = (1 << 0), TEST_FLAGS_SECOND = (1 << 1), TEST_FLAGS_THIRD = (1 << 2), TEST_FLAGS_FOURTH = (1 << 3), TEST_FLAGS_FIFTH = (1 << 4), TEST_FLAGS_SIXTH = (1 << 5), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, { "fifth", (1 << 4) }, { "sixth", (1 << 5) }, }; static const unsigned char yaml[] = "key:\n" " - first\n" " - map:\n" " a:\n" " b:\n"; struct target_struct { enum test_flags a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLAGS("key", CYAML_FLAG_STRICT, struct target_struct, a, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_UNEXPECTED_EVENT) { 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 enum, but string is not allowed. * * \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_enum_bad_string( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_enum { TEST_ENUM_FIRST, TEST_ENUM_SECOND, TEST_ENUM_THIRD, TEST_ENUM__COUNT, }; static const cyaml_strval_t strings[TEST_ENUM__COUNT] = { [TEST_ENUM_FIRST] = { "first", 0 }, [TEST_ENUM_SECOND] = { "second", 1 }, [TEST_ENUM_THIRD] = { "third", 2 }, }; static const unsigned char yaml[] = "key: fourth\n"; struct target_struct { enum test_enum a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_ENUM("key", CYAML_FLAG_DEFAULT, struct target_struct, a, strings, TEST_ENUM__COUNT), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 flags but YAML has bad flag string. * * \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_flags_bad_string( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_flags { TEST_FLAGS_NONE = 0, TEST_FLAGS_FIRST = (1 << 0), TEST_FLAGS_SECOND = (1 << 1), TEST_FLAGS_THIRD = (1 << 2), TEST_FLAGS_FOURTH = (1 << 3), TEST_FLAGS_FIFTH = (1 << 4), TEST_FLAGS_SIXTH = (1 << 5), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, { "fifth", (1 << 4) }, { "sixth", (1 << 5) }, }; static const unsigned char yaml[] = "key:\n" " - first\n" " - seventh\n"; struct target_struct { enum test_flags a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLAGS("key", CYAML_FLAG_DEFAULT, struct target_struct, a, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 saving when schema expects strict enum, but value not allowed. * * \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_save_schema_strict_enum_bad_value( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_enum { TEST_ENUM_FIRST, TEST_ENUM_SECOND, TEST_ENUM_THIRD, TEST_ENUM__COUNT, }; static const cyaml_strval_t strings[TEST_ENUM__COUNT] = { [TEST_ENUM_FIRST] = { "first", 0 }, [TEST_ENUM_SECOND] = { "second", 1 }, [TEST_ENUM_THIRD] = { "third", 2 }, }; struct target_struct { enum test_enum a; } data = { .a = 876, }; char *buffer = NULL; size_t len = 0; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_ENUM("key", CYAML_FLAG_STRICT, struct target_struct, a, strings, TEST_ENUM__COUNT), 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 = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_INVALID_VALUE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading when schema expects strict enum but YAML has bad string. * * \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_strict_enum_bad_string( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_enum { TEST_ENUM_FIRST, TEST_ENUM_SECOND, TEST_ENUM_THIRD, TEST_ENUM__COUNT, }; static const cyaml_strval_t strings[TEST_ENUM__COUNT] = { [TEST_ENUM_FIRST] = { "first", 0 }, [TEST_ENUM_SECOND] = { "second", 1 }, [TEST_ENUM_THIRD] = { "third", 2 }, }; static const unsigned char yaml[] = "key: fourth\n"; struct target_struct { enum test_enum a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_ENUM("key", CYAML_FLAG_STRICT, struct target_struct, a, strings, TEST_ENUM__COUNT), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 saving when schema expects strict flags, but value not allowed. * * \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_save_schema_strict_flags_bad_value( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_flags { TEST_FLAGS_NONE = 0, TEST_FLAGS_FIRST = (1 << 0), TEST_FLAGS_SECOND = (1 << 1), TEST_FLAGS_THIRD = (1 << 2), TEST_FLAGS_FOURTH = (1 << 3), TEST_FLAGS_FIFTH = (1 << 4), TEST_FLAGS_SIXTH = (1 << 5), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, { "fifth", (1 << 4) }, { "sixth", (1 << 5) }, }; struct target_struct { enum test_flags a; } data = { .a = TEST_FLAGS_SECOND | TEST_FLAGS_FIFTH | (1 << 9), }; char *buffer = NULL; size_t len = 0; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLAGS("key", CYAML_FLAG_STRICT, struct target_struct, a, 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 = { .buffer = &buffer, .config = config, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_save_data(&buffer, &len, config, &top_schema, &data, 0); if (err != CYAML_ERR_INVALID_VALUE) { return ttest_fail(&tc, cyaml_strerror(err)); } if (buffer != NULL || len != 0) { return ttest_fail(&tc, "Buffer/len not untouched."); } return ttest_pass(&tc); } /** * Test loading when schema expects strict flags but YAML has bad string. * * \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_strict_flags_bad_string( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_flags { TEST_FLAGS_NONE = 0, TEST_FLAGS_FIRST = (1 << 0), TEST_FLAGS_SECOND = (1 << 1), TEST_FLAGS_THIRD = (1 << 2), TEST_FLAGS_FOURTH = (1 << 3), TEST_FLAGS_FIFTH = (1 << 4), TEST_FLAGS_SIXTH = (1 << 5), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, { "fifth", (1 << 4) }, { "sixth", (1 << 5) }, }; static const unsigned char yaml[] = "key:\n" " - first\n" " - seventh\n"; struct target_struct { enum test_flags a; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLAGS("key", CYAML_FLAG_STRICT, struct target_struct, a, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 int, but YAML has sequence. * * \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_expect_int_read_seq( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key:\n" " - 90"; struct target_struct { int value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("key", CYAML_FLAG_DEFAULT, struct target_struct, value), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 int, but YAML ends. * * \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_expect_int_read_end_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key:\n"; struct target_struct { int value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("key", CYAML_FLAG_DEFAULT, struct target_struct, value), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 int, but YAML ends. * * \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_expect_int_read_end_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key: |" "..."; struct target_struct { int value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_INT("key", CYAML_FLAG_DEFAULT, struct target_struct, value), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_LIBYAML_PARSER) { 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 flags, but YAML has scalar. * * \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_expect_flags_read_scalar( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, { "fifth", (1 << 4) }, { "sixth", (1 << 5) }, }; static const unsigned char yaml[] = "key: first\n"; struct target_struct { int value; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLAGS("key", CYAML_FLAG_DEFAULT, struct target_struct, value, 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 mapping, but YAML has scalar. * * \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_expect_mapping_read_scalar( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key: scalar\n"; struct value_s { int a; }; struct target_struct { struct value_s test_value_mapping; } *data_tgt = NULL; static const struct cyaml_schema_field test_mapping_schema[] = { CYAML_FIELD_INT("a", CYAML_FLAG_DEFAULT, struct value_s, a), CYAML_FIELD_END }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_MAPPING("key", CYAML_FLAG_DEFAULT, struct target_struct, test_value_mapping, test_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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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 sequence, but YAML has scalar. * * \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_expect_sequence_read_scalar( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "key: foo\n"; struct target_struct { int *a; unsigned a_count; } *data_tgt = NULL; static const struct cyaml_schema_value entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, *(data_tgt->a)), }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_SEQUENCE("key", CYAML_FLAG_POINTER, struct target_struct, a, &entry_schema, 0, CYAML_UNLIMITED), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } 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, with all memory allocation failure at every possible point. * * \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_free_null( ttest_report_ctx_t *report, const cyaml_config_t *config) { ttest_ctx_t tc; if (!ttest_start(report, __func__, NULL, NULL, &tc)) { return true; } UNUSED(config); cyaml_mem(NULL, NULL, 0); return ttest_pass(&tc); } /** Context for allocation failure tests. */ struct test_cyaml_mem_ctx { unsigned required; unsigned fail; unsigned current; }; /* * Allocation counter. * * Used to count all allocations made when loading an input. * * \param[in] ctx Allocation context. * \param[in] ptr Pointer to allocation to resize or NULL. * \param[in] size Size to set allocation to. * \return Pointer to new allocation, or NULL on failure. */ static void * test_cyaml_mem_count_allocs( void *ctx, void *ptr, size_t size) { struct test_cyaml_mem_ctx *mem_ctx = ctx; if (size == 0) { free(ptr); return NULL; } mem_ctx->required++; return realloc(ptr, size); } /** * Allocation failure tester. * * Used to make specific allocation fail. * * \param[in] ctx Allocation context. * \param[in] ptr Pointer to allocation to resize or NULL. * \param[in] size Size to set allocation to. * \return Pointer to new allocation, or NULL on failure. */ static void * test_cyaml_mem_fail( void *ctx, void *ptr, size_t size) { struct test_cyaml_mem_ctx *mem_ctx = ctx; if (size == 0) { free(ptr); return NULL; } if (mem_ctx->current == mem_ctx->fail) { return NULL; } mem_ctx->current++; return realloc(ptr, size); } /** * Test loading, with all memory allocation failure at every possible point. * * \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_alloc_oom_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { cyaml_config_t cfg = *config; static const unsigned char yaml[] = "animals:\n" " - kind: cat\n" " sound: meow\n" " position: [ 1, 2, 1]\n" " - kind: snake\n" " sound: hiss\n" " position: [ 3, 1, 0]\n"; struct animal_s { char *kind; char *sound; int *position; }; struct target_struct { struct animal_s **animal; uint32_t animal_count; } *data_tgt = NULL; static const struct cyaml_schema_value position_entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, int), }; static const struct cyaml_schema_field animal_schema[] = { CYAML_FIELD_STRING_PTR("kind", CYAML_FLAG_POINTER, struct animal_s, kind, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("sound", CYAML_FLAG_POINTER, struct animal_s, sound, 0, CYAML_UNLIMITED), CYAML_FIELD_SEQUENCE_FIXED("position", CYAML_FLAG_POINTER, struct animal_s, position, &position_entry_schema, 3), CYAML_FIELD_END }; static const struct cyaml_schema_value animal_entry_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, **(data_tgt->animal), animal_schema), }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_SEQUENCE("animals", CYAML_FLAG_POINTER, struct target_struct, animal, &animal_entry_schema, 0, CYAML_UNLIMITED), 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 = &cfg, .schema = &top_schema, }; cyaml_err_t err; struct test_cyaml_mem_ctx mem_ctx = { .required = 0, }; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } /* * First we load the YAML with the counting allocation function, * to find the number of allocations required to load the document. * This is deterministic. */ cfg.mem_fn = test_cyaml_mem_count_allocs; cfg.mem_ctx = &mem_ctx; err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_OK) { return ttest_fail(&tc, cyaml_strerror(err)); } if (mem_ctx.required == 0) { return ttest_fail(&tc, "There were no allocations."); } /* Now free what was loaded. */ cyaml_free(config, &top_schema, data_tgt, 0); data_tgt = NULL; /* * Now we load the document multiple times, forcing every possible * allocation to fail. */ cfg.mem_fn = test_cyaml_mem_fail; for (mem_ctx.fail = 0; mem_ctx.fail < mem_ctx.required; mem_ctx.fail++) { mem_ctx.current = 0; err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_OOM) { return ttest_fail(&tc, cyaml_strerror(err)); } /* Now free what was loaded. */ cyaml_free(config, &top_schema, data_tgt, 0); data_tgt = NULL; } return ttest_pass(&tc); } /** * Test loading, with all memory allocation failure at every possible point. * * Uses aliases and anchors, to exercies the event/anchor recording error * paths too. * * \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_alloc_oom_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_f { NONE = 0, FIRST = (1 << 0), SECOND = (1 << 1), THIRD = (1 << 2), FOURTH = (1 << 3), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, }; cyaml_config_t cfg = *config; static const unsigned char yaml[] = "anchors:\n" " - &a1 {" " kind: cat,\n" " sound: meow,\n" " position: &a2 [ 1, &my_value 2, 1],\n" " flags: &a3 [\n" " first,\n" " &a4 second,\n" " third,\n" " fourth,\n" " ]\n" " }\n" " - kind: snake\n" " sound: &a5 hiss\n" " position: &a6 [ 3, 1, 0]\n" " flags: &a7 [\n" " first,\n" " second,\n" " third,\n" " fourth,\n" " ]\n" "animals:\n" " - *a1\n" " - kind: snake\n" " sound: *a5\n" " position: *a6\n" " flags: *a7\n" " value: *my_value\n"; struct animal_s { char *kind; char *sound; int **position; unsigned position_count; enum test_f *flags; int value; }; struct target_struct { struct animal_s **animal; uint32_t animal_count; } *data_tgt = NULL; static const struct cyaml_schema_value position_entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_POINTER, int), }; static const struct cyaml_schema_field animal_schema[] = { CYAML_FIELD_STRING_PTR("kind", CYAML_FLAG_POINTER, struct animal_s, kind, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("sound", CYAML_FLAG_POINTER, struct animal_s, sound, 0, CYAML_UNLIMITED), CYAML_FIELD_SEQUENCE("position", CYAML_FLAG_POINTER, struct animal_s, position, &position_entry_schema, 0, CYAML_UNLIMITED), CYAML_FIELD_FLAGS("flags", CYAML_FLAG_STRICT | CYAML_FLAG_POINTER, struct animal_s, flags, strings, 4), CYAML_FIELD_INT("value", CYAML_FLAG_OPTIONAL, struct animal_s, value), CYAML_FIELD_END }; static const struct cyaml_schema_value animal_entry_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, **(data_tgt->animal), animal_schema), }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_IGNORE("anchors", CYAML_FLAG_OPTIONAL), CYAML_FIELD_SEQUENCE("animals", CYAML_FLAG_POINTER, struct target_struct, animal, &animal_entry_schema, 0, CYAML_UNLIMITED), CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; struct test_cyaml_mem_ctx mem_ctx = { .required = 0, }; test_data_t td = { .data = (cyaml_data_t **) &data_tgt, .config = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } /* * First we load the YAML with the counting allocation function, * to find the number of allocations required to load the document. * This is deterministic. */ cfg.mem_fn = test_cyaml_mem_count_allocs; cfg.mem_ctx = &mem_ctx; err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_OK) { return ttest_fail(&tc, cyaml_strerror(err)); } if (mem_ctx.required == 0) { return ttest_fail(&tc, "There were no allocations."); } /* Now free what was loaded. */ cyaml_free(config, &top_schema, data_tgt, 0); data_tgt = NULL; /* * Now we load the document multiple times, forcing every possible * allocation to fail. */ cfg.mem_fn = test_cyaml_mem_fail; for (mem_ctx.fail = 0; mem_ctx.fail < mem_ctx.required; mem_ctx.fail++) { mem_ctx.current = 0; err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_OOM) { return ttest_fail(&tc, cyaml_strerror(err)); } /* Now free what was loaded. */ cyaml_free(config, &top_schema, data_tgt, 0); data_tgt = NULL; } return ttest_pass(&tc); } /** * Test saving, with memory allocation failure at every possible point. * * \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_save_alloc_oom_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { cyaml_config_t cfg = *config; static const unsigned char yaml[] = "animals:\n" " - kind: cat\n" " sound: meow\n" " position: [ 1, 2, 1]\n" " - kind: snake\n" " sound: hiss\n" " position: [ 3, 1, 0]\n"; struct animal_s { char *kind; char *sound; int *position; }; struct target_struct { struct animal_s **animal; uint32_t animal_count; } *data_tgt = NULL; static const struct cyaml_schema_value position_entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_DEFAULT, int), }; static const struct cyaml_schema_field animal_schema[] = { CYAML_FIELD_STRING_PTR("kind", CYAML_FLAG_POINTER, struct animal_s, kind, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("sound", CYAML_FLAG_POINTER, struct animal_s, sound, 0, CYAML_UNLIMITED), CYAML_FIELD_SEQUENCE_FIXED("position", CYAML_FLAG_POINTER, struct animal_s, position, &position_entry_schema, 3), CYAML_FIELD_END }; static const struct cyaml_schema_value animal_entry_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, **(data_tgt->animal), animal_schema), }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_SEQUENCE("animals", CYAML_FLAG_POINTER, struct target_struct, animal, &animal_entry_schema, 0, CYAML_UNLIMITED), CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; struct test_cyaml_mem_ctx mem_ctx = { .required = 0, }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .data = (cyaml_data_t **) &data_tgt, .config = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } /* First we load the YAML, so we have something to test saving. */ err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_OK) { return ttest_fail(&tc, cyaml_strerror(err)); } /* * First we load the YAML with the counting allocation function, * to find the number of allocations required to load the document. * This is deterministic. */ cfg.mem_fn = test_cyaml_mem_count_allocs; cfg.mem_ctx = &mem_ctx; err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, data_tgt, 0); if (err != CYAML_OK) { return ttest_fail(&tc, cyaml_strerror(err)); } if (mem_ctx.required == 0) { return ttest_fail(&tc, "There were no allocations."); } /* Now free what was loaded. */ cyaml_mem(&mem_ctx, buffer, 0); buffer = NULL; len = 0; /* * Now we load the document multiple times, forcing every possible * allocation to fail. */ cfg.mem_fn = test_cyaml_mem_fail; for (mem_ctx.fail = 0; mem_ctx.fail < mem_ctx.required; mem_ctx.fail++) { mem_ctx.current = 0; err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, data_tgt, 0); if (err != CYAML_ERR_OOM) { return ttest_fail(&tc, cyaml_strerror(err)); } /* Now free what was loaded. */ cyaml_mem(&mem_ctx, buffer, 0); buffer = NULL; len = 0; } return ttest_pass(&tc); } /** * Test loading, with all memory allocation failure at every possible point. * * \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_save_alloc_oom_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_f { NONE = 0, FIRST = (1 << 0), SECOND = (1 << 1), THIRD = (1 << 2), FOURTH = (1 << 3), }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, }; cyaml_config_t cfg = *config; static const unsigned char yaml[] = "animals:\n" " - kind: cat\n" " sound: meow\n" " position: [ 1, 2, 1]\n" " flags:\n" " - first\n" " - second\n" " - third\n" " - fourth\n" " - kind: snake\n" " sound: hiss\n" " position: [ 3, 1, 0]\n" " flags:\n" " - first\n" " - second\n" " - third\n" " - fourth\n"; struct animal_s { char *kind; char *sound; int **position; unsigned position_count; enum test_f *flags; }; struct target_struct { struct animal_s **animal; uint32_t animal_count; } *data_tgt = NULL; static const struct cyaml_schema_value position_entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_POINTER, int), }; static const struct cyaml_schema_field animal_schema[] = { CYAML_FIELD_STRING_PTR("kind", CYAML_FLAG_POINTER, struct animal_s, kind, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("sound", CYAML_FLAG_POINTER, struct animal_s, sound, 0, CYAML_UNLIMITED), CYAML_FIELD_SEQUENCE("position", CYAML_FLAG_POINTER, struct animal_s, position, &position_entry_schema, 0, CYAML_UNLIMITED), CYAML_FIELD_FLAGS("flags", CYAML_FLAG_STRICT | CYAML_FLAG_POINTER, struct animal_s, flags, strings, 4), CYAML_FIELD_END }; static const struct cyaml_schema_value animal_entry_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, **(data_tgt->animal), animal_schema), }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_SEQUENCE("animals", CYAML_FLAG_POINTER, struct target_struct, animal, &animal_entry_schema, 0, CYAML_UNLIMITED), CYAML_FIELD_END }; static const struct cyaml_schema_value top_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct target_struct, mapping_schema), }; struct test_cyaml_mem_ctx mem_ctx = { .required = 0, }; char *buffer = NULL; size_t len = 0; test_data_t td = { .buffer = &buffer, .data = (cyaml_data_t **) &data_tgt, .config = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } /* First we load the YAML, so we have something to test saving. */ err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_OK) { return ttest_fail(&tc, cyaml_strerror(err)); } /* * First we load the YAML with the counting allocation function, * to find the number of allocations required to load the document. * This is deterministic. */ cfg.mem_fn = test_cyaml_mem_count_allocs; cfg.mem_ctx = &mem_ctx; err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, data_tgt, 0); if (err != CYAML_OK) { return ttest_fail(&tc, cyaml_strerror(err)); } if (mem_ctx.required == 0) { return ttest_fail(&tc, "There were no allocations."); } /* Now free what was loaded. */ cyaml_mem(&mem_ctx, buffer, 0); buffer = NULL; len = 0; /* * Now we load the document multiple times, forcing every possible * allocation to fail. */ cfg.mem_fn = test_cyaml_mem_fail; for (mem_ctx.fail = 0; mem_ctx.fail < mem_ctx.required; mem_ctx.fail++) { mem_ctx.current = 0; err = cyaml_save_data(&buffer, &len, &cfg, &top_schema, data_tgt, 0); if (err != CYAML_ERR_OOM) { return ttest_fail(&tc, cyaml_strerror(err)); } /* Now free what was loaded. */ cyaml_mem(&mem_ctx, buffer, 0); buffer = NULL; len = 0; } return ttest_pass(&tc); } /** * Test loading a flag with an aliased value. * * \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_flag_value_alias( ttest_report_ctx_t *report, const cyaml_config_t *config) { cyaml_config_t cfg = *config; struct target_struct { unsigned a; unsigned b; }; static const cyaml_strval_t str[] = { { "one", (1 << 0) }, { "two", (1 << 1) }, { "three", (1 << 2) }, { "four", (1 << 3) }, { "five", (1 << 4) }, }; static const unsigned char yaml[] = "a: \n" " - &foo one\n" " - two\n" " - five\n" "b:\n" " - *foo\n"; struct target_struct *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_FLAGS("a", CYAML_FLAG_DEFAULT, struct target_struct, a, str, 5), CYAML_FIELD_FLAGS("b", CYAML_FLAG_DEFAULT, struct target_struct, b, str, 5), 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 = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; cfg.flags |= CYAML_CFG_NO_ALIAS; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_ALIAS) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading a bitfield with an aliased value. * * \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_bitfield_value_alias_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { cyaml_config_t cfg = *config; static const cyaml_bitdef_t bitvals[] = { { .name = "7", .offset = 0, .bits = 1 }, { .name = "a", .offset = 1, .bits = 2 }, { .name = "b", .offset = 3, .bits = 7 }, { .name = "c", .offset = 10, .bits = 32 }, { .name = "d", .offset = 42, .bits = 8 }, { .name = "e", .offset = 50, .bits = 14 }, }; static const unsigned char yaml[] = "test_bitfield:\n" " a: &foo 2\n" " b: 0x7f\n" " c: 0xffffffff\n" " d: 0xff\n" " e: 0x3fff\n" "test_bitfield2:\n" " *foo: 1\n" " b: 0x7f\n" " c: 0xffffffff\n" " d: 0xff\n" " e: 0x3fff\n"; struct target_struct { uint64_t test_value_bitfield; uint64_t test_value_bitfield2; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_BITFIELD("test_bitfield", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield, bitvals, CYAML_ARRAY_LEN(bitvals)), CYAML_FIELD_BITFIELD("test_bitfield2", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield2, bitvals, CYAML_ARRAY_LEN(bitvals)), 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 = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; cfg.flags |= CYAML_CFG_NO_ALIAS; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_ALIAS) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading a bitfield with an aliased value. * * \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_bitfield_value_alias_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { cyaml_config_t cfg = *config; static const cyaml_bitdef_t bitvals[] = { { .name = "7", .offset = 0, .bits = 1 }, { .name = "a", .offset = 1, .bits = 2 }, { .name = "b", .offset = 3, .bits = 7 }, { .name = "c", .offset = 10, .bits = 32 }, { .name = "d", .offset = 42, .bits = 8 }, { .name = "e", .offset = 50, .bits = 14 }, }; static const unsigned char yaml[] = "test_bitfield:\n" " a: &foo 2\n" " b: 0x7f\n" " c: 0xffffffff\n" " d: 0xff\n" " e: 0x3fff\n" "test_bitfield2:\n" " a: *foo\n" " b: 0x7f\n" " c: 0xffffffff\n" " d: 0xff\n" " e: 0x3fff\n"; struct target_struct { uint64_t test_value_bitfield; uint64_t test_value_bitfield2; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_BITFIELD("test_bitfield", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield, bitvals, CYAML_ARRAY_LEN(bitvals)), CYAML_FIELD_BITFIELD("test_bitfield2", CYAML_FLAG_DEFAULT, struct target_struct, test_value_bitfield2, bitvals, CYAML_ARRAY_LEN(bitvals)), 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 = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; cfg.flags |= CYAML_CFG_NO_ALIAS; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_ALIAS) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading a mapping with an aliased value. * * \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_mapping_key_alias( ttest_report_ctx_t *report, const cyaml_config_t *config) { cyaml_config_t cfg = *config; struct target_struct { char *a; char *b; char *c; char *d; }; static const unsigned char yaml[] = "a: &example b\n" "*example: test\n" "c: meh\n" "d: foo\n"; struct target_struct *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_STRING_PTR("a", CYAML_FLAG_POINTER, struct target_struct, a, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("b", CYAML_FLAG_POINTER, struct target_struct, b, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("c", CYAML_FLAG_POINTER, struct target_struct, c, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("d", CYAML_FLAG_POINTER, struct target_struct, d, 0, CYAML_UNLIMITED), 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 = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; cfg.flags |= CYAML_CFG_NO_ALIAS; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_ALIAS) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading a mapping with an aliased value. * * \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_mapping_value_alias_1( ttest_report_ctx_t *report, const cyaml_config_t *config) { cyaml_config_t cfg = *config; struct target_struct { char *a; char *b; char *c; char *d; }; static const unsigned char yaml[] = "a: 9\n" "b: 90\n" "c: &foo 900\n" "d: *foo\n"; struct target_struct *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_STRING_PTR("a", CYAML_FLAG_POINTER, struct target_struct, a, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("b", CYAML_FLAG_POINTER, struct target_struct, b, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("c", CYAML_FLAG_POINTER, struct target_struct, c, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("d", CYAML_FLAG_POINTER, struct target_struct, d, 0, CYAML_UNLIMITED), 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 = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; cfg.flags |= CYAML_CFG_NO_ALIAS; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_ALIAS) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading a mapping with an aliased value. * * \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_mapping_value_alias_2( ttest_report_ctx_t *report, const cyaml_config_t *config) { cyaml_config_t cfg = *config; struct target_struct { char *a; char *b; char *c; char *d; }; static const unsigned char yaml[] = "a: 9\n" "b: &foo d\n" "c: *d\n"; struct target_struct *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_STRING_PTR("a", CYAML_FLAG_POINTER, struct target_struct, a, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("b", CYAML_FLAG_POINTER, struct target_struct, b, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("d", CYAML_FLAG_POINTER, struct target_struct, d, 0, CYAML_UNLIMITED), 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 = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; cfg.flags |= CYAML_CFG_NO_ALIAS | CYAML_CFG_IGNORE_UNKNOWN_KEYS; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_ALIAS) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading a mapping with an aliased value. * * \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_mapping_value_alias_3( ttest_report_ctx_t *report, const cyaml_config_t *config) { cyaml_config_t cfg = *config; struct target_struct { char *a; char *b; }; static const unsigned char yaml[] = "a: 9\n" "b: &foo d\n" "c: [a, b, c, *foo]\n"; struct target_struct *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_STRING_PTR("a", CYAML_FLAG_POINTER, struct target_struct, a, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("b", CYAML_FLAG_POINTER, struct target_struct, b, 0, CYAML_UNLIMITED), CYAML_FIELD_IGNORE("c", CYAML_FLAG_DEFAULT), 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 = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; cfg.flags |= CYAML_CFG_NO_ALIAS; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_ALIAS) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading with an aliased string value. * * \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_invalid_alias( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "test_string_anchor: &foo Hello World!\n" "test_string: *bar\n" "test_int: 9\n"; struct target_struct { char * test_value_string; int test_value_int; } *data_tgt = NULL; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_IGNORE("test_string_anchor", CYAML_FLAG_OPTIONAL), CYAML_FIELD_STRING_PTR("test_string", CYAML_FLAG_POINTER, struct target_struct, test_value_string, 0, CYAML_UNLIMITED), CYAML_FIELD_INT("test_int", CYAML_FLAG_DEFAULT, struct target_struct, test_value_int), 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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_ALIAS) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** * Test loading an incomplete alias. * * \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_incomplete_alias( ttest_report_ctx_t *report, const cyaml_config_t *config) { static const unsigned char yaml[] = "anchors:\n" " - &a1 {\n" " a: 777,\n" " b: *a1,\n" " }\n" "test: *a1\n"; struct my_test { int a; char *b; }; struct target_struct { struct my_test test; } *data_tgt = NULL; static const struct cyaml_schema_field inner_mapping_schema[] = { CYAML_FIELD_INT("a", CYAML_FLAG_DEFAULT, struct my_test, a), CYAML_FIELD_STRING_PTR("b", CYAML_FLAG_POINTER, struct my_test, b, 0, CYAML_UNLIMITED), CYAML_FIELD_END }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_IGNORE("anchors", CYAML_FLAG_OPTIONAL), CYAML_FIELD_MAPPING("test", CYAML_FLAG_DEFAULT, struct target_struct, test, inner_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; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } err = cyaml_load_data(yaml, YAML_LEN(yaml), config, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err != CYAML_ERR_INVALID_ALIAS) { return ttest_fail(&tc, cyaml_strerror(err)); } return ttest_pass(&tc); } /** Structure for log messages checking. */ struct log_check { unsigned string_count_expected; /**< Number of expected log messages. */ const char *const *strings; /**< Array of expected log messages. */ unsigned string_count; /**< Number of log messages captured. */ bool error; /**< Whether a logging error has been found. */ }; /** * Initialise a log check structure for a given log string vector. * * \param[in] lc The log check structure to initialise. * \param[in] strv A string vector containing expected log messages. * \return true on success, false otherwise. */ static inline bool log_check_init( struct log_check *lc, const char *const *strv) { if (lc == NULL) { return false; } lc->string_count_expected = 0; lc->string_count = 0; lc->strings = strv; lc->error = false; while (strv[lc->string_count_expected] != NULL) { lc->string_count_expected++; } return true; } static struct log_check lc; /** * CYAML log function, for checking logs. * * Uses the lc static state. * * \param[in] level Log level of message to log. * \param[in] ctx Client's private logging context. * \param[in] fmt Format string for message to log. * \param[in] args Additional arguments used by fmt. */ static void cyaml_log_check( cyaml_log_t level, void *ctx, const char *fmt, va_list args) { int ret; size_t len; char buffer[128]; (void)(ctx); if (level < CYAML_LOG_ERROR) { /* We only care that critical log messages emerge. */ return; } ret = vsnprintf(buffer, sizeof(buffer), fmt, args); if (ret <= 0) { fprintf(stderr, "TEST ERROR: Logging error\n"); return; } len = (unsigned)ret; if (len >= sizeof(buffer)) { fprintf(stderr, "TEST ERROR: Buffer too small\n"); assert(len < sizeof(buffer)); return; } if (lc.string_count >= lc.string_count_expected) { fprintf(stderr, "ERROR: More log messages than expected\n"); fprintf(stderr, " got: %s", buffer); lc.error |= true; goto out; } if (strcmp(lc.strings[lc.string_count], buffer) != 0) { fprintf(stderr, "ERROR: Unexpected log message\n"); fprintf(stderr, " got: %s", buffer); fprintf(stderr, "expected: %s", lc.strings[lc.string_count]); lc.error |= true; goto out; } out: lc.string_count++; } /** * Check that the logging contains the expected information. * * \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_log( ttest_report_ctx_t *report, const cyaml_config_t *config) { enum test_f { NONE = 0, FIRST = (1 << 0), SECOND = (1 << 1), THIRD = (1 << 2), FOURTH = (1 << 3), }; static const char * const expected_log[] = { "Load: Invalid INT value: 'foo'\n", "Load: Backtrace:\n", " in sequence entry '2' (line: 5, column: 26)\n", " in mapping field 'position' (line: 5, column: 17)\n", " in sequence entry '1' (line: 2, column: 5)\n", " in mapping field 'animals' (line: 23, column: 3)\n", NULL }; static const cyaml_strval_t strings[] = { { "first", (1 << 0) }, { "second", (1 << 1) }, { "third", (1 << 2) }, { "fourth", (1 << 3) }, }; cyaml_config_t cfg = *config; static const unsigned char yaml[] = "anchors:\n" " - &a1 {\n" " kind: cat,\n" " sound: meow,\n" " position: &a2 [ 1, &my_value foo, 1],\n" " flags: &a3 [\n" " first,\n" " &a4 second,\n" " third,\n" " fourth,\n" " ]\n" " }\n" " - kind: snake\n" " sound: &a5 hiss\n" " position: &a6 [ 3, 1, 0]\n" " flags: &a7 [\n" " first,\n" " second,\n" " third,\n" " fourth,\n" " ]\n" "animals:\n" " - *a1\n" " - kind: snake\n" " sound: *a5\n" " position: *a6\n" " flags: *a7\n" " value: *my_value\n"; struct animal_s { char *kind; char *sound; int **position; unsigned position_count; enum test_f *flags; int value; }; struct target_struct { struct animal_s **animal; uint32_t animal_count; } *data_tgt = NULL; static const struct cyaml_schema_value position_entry_schema = { CYAML_VALUE_INT(CYAML_FLAG_POINTER, int), }; static const struct cyaml_schema_field animal_schema[] = { CYAML_FIELD_STRING_PTR("kind", CYAML_FLAG_POINTER, struct animal_s, kind, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("sound", CYAML_FLAG_POINTER, struct animal_s, sound, 0, CYAML_UNLIMITED), CYAML_FIELD_SEQUENCE("position", CYAML_FLAG_POINTER, struct animal_s, position, &position_entry_schema, 0, CYAML_UNLIMITED), CYAML_FIELD_FLAGS("flags", CYAML_FLAG_STRICT | CYAML_FLAG_POINTER, struct animal_s, flags, strings, 4), CYAML_FIELD_INT("value", CYAML_FLAG_OPTIONAL, struct animal_s, value), CYAML_FIELD_END }; static const struct cyaml_schema_value animal_entry_schema = { CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, **(data_tgt->animal), animal_schema), }; static const struct cyaml_schema_field mapping_schema[] = { CYAML_FIELD_IGNORE("anchors", CYAML_FLAG_OPTIONAL), CYAML_FIELD_SEQUENCE("animals", CYAML_FLAG_POINTER, struct target_struct, animal, &animal_entry_schema, 0, CYAML_UNLIMITED), 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 = &cfg, .schema = &top_schema, }; cyaml_err_t err; ttest_ctx_t tc; if (!ttest_start(report, __func__, cyaml_cleanup, &td, &tc)) { return true; } log_check_init(&lc, expected_log); cfg.log_fn = cyaml_log_check; err = cyaml_load_data(yaml, YAML_LEN(yaml), &cfg, &top_schema, (cyaml_data_t **) &data_tgt, NULL); if (err == CYAML_OK) { return ttest_fail(&tc, cyaml_strerror(err)); } if (lc.error == true) { return ttest_fail(&tc, "Unexpected log message"); } if (lc.string_count_expected > lc.string_count) { return ttest_fail(&tc, "Missing log message(s)"); } return ttest_pass(&tc); } /** * Run the CYAML error unit tests. * * \param[in] rc The ttest report context. * \param[in] log_level CYAML log level. * \param[in] log_fn CYAML logging function, or NULL. * \return true iff all unit tests pass, otherwise false. */ bool errs_tests( ttest_report_ctx_t *rc, cyaml_log_t log_level, cyaml_log_fn_t log_fn) { bool pass = true; cyaml_config_t config = { .log_fn = log_fn, .mem_fn = cyaml_mem, .log_level = log_level, .flags = CYAML_CFG_DEFAULT, }; /* Since we expect loads of error logging for these tests, * suppress log output if required log level is greater * than \ref CYAML_LOG_INFO. */ if (log_level > CYAML_LOG_INFO) { config.log_fn = NULL; } ttest_heading(rc, "Bad parameter tests"); pass &= test_err_load_null_data(rc, &config); pass &= test_err_save_null_data(rc, &config); pass &= test_err_load_null_config(rc, &config); pass &= test_err_save_null_config(rc, &config); pass &= test_err_load_null_mem_fn(rc, &config); pass &= test_err_save_null_mem_fn(rc, &config); pass &= test_err_load_null_schema(rc, &config); pass &= test_err_save_null_schema(rc, &config); pass &= test_err_load_schema_top_level_non_pointer(rc, &config); pass &= test_err_save_schema_top_level_non_pointer(rc, &config); pass &= test_err_load_schema_top_level_sequence_no_count(rc, &config); pass &= test_err_load_schema_top_level_not_sequence_count(rc, &config); pass &= test_err_save_schema_top_level_not_sequence_count(rc, &config); ttest_heading(rc, "Bad schema tests"); pass &= test_err_load_schema_bad_type(rc, &config); pass &= test_err_save_schema_bad_type(rc, &config); pass &= test_err_load_schema_bad_bitfield(rc, &config); pass &= test_err_save_schema_bad_bitfield(rc, &config); pass &= test_err_load_schema_string_min_max(rc, &config); pass &= test_err_load_schema_bad_data_size_1(rc, &config); pass &= test_err_load_schema_bad_data_size_2(rc, &config); pass &= test_err_load_schema_bad_data_size_3(rc, &config); pass &= test_err_load_schema_bad_data_size_4(rc, &config); pass &= test_err_load_schema_bad_data_size_5(rc, &config); pass &= test_err_load_schema_bad_data_size_6(rc, &config); pass &= test_err_load_schema_bad_data_size_7(rc, &config); pass &= test_err_load_schema_bad_data_size_8(rc, &config); pass &= test_err_load_schema_bad_data_size_9(rc, &config); pass &= test_err_save_schema_bad_data_size_1(rc, &config); pass &= test_err_save_schema_bad_data_size_2(rc, &config); pass &= test_err_save_schema_bad_data_size_3(rc, &config); pass &= test_err_save_schema_bad_data_size_4(rc, &config); pass &= test_err_save_schema_bad_data_size_5(rc, &config); pass &= test_err_save_schema_bad_data_size_6(rc, &config); pass &= test_err_save_schema_bad_data_size_7(rc, &config); pass &= test_err_save_schema_bad_data_size_8(rc, &config); pass &= test_err_load_schema_sequence_min_max(rc, &config); pass &= test_err_save_schema_sequence_min_max(rc, &config); pass &= test_err_load_schema_bad_data_size_float(rc, &config); pass &= test_err_load_schema_sequence_in_sequence(rc, &config); pass &= test_err_save_schema_sequence_in_sequence(rc, &config); ttest_heading(rc, "YAML / schema mismatch: bad values"); pass &= test_err_load_non_scalar_mapping_key(rc, &config); pass &= test_err_load_schema_invalid_value_uint(rc, &config); pass &= test_err_load_schema_invalid_value_string(rc, &config); pass &= test_err_load_schema_invalid_value_flags_1(rc, &config); pass &= test_err_load_schema_invalid_value_flags_2(rc, &config); pass &= test_err_load_schema_invalid_value_flags_3(rc, &config); pass &= test_err_save_schema_invalid_value_null_ptr(rc, &config); pass &= test_err_load_schema_invalid_value_int_junk(rc, &config); pass &= test_err_load_schema_invalid_value_uint_junk(rc, &config); pass &= test_err_load_schema_invalid_value_flags_junk(rc, &config); pass &= test_err_load_schema_invalid_value_bitfield_1(rc, &config); pass &= test_err_load_schema_invalid_value_bitfield_2(rc, &config); pass &= test_err_load_schema_invalid_value_bitfield_3(rc, &config); pass &= test_err_load_schema_invalid_value_bitfield_4(rc, &config); pass &= test_err_load_schema_invalid_value_bitfield_5(rc, &config); pass &= test_err_load_schema_invalid_value_bitfield_6(rc, &config); pass &= test_err_load_schema_invalid_value_float_junk(rc, &config); pass &= test_err_load_schema_invalid_value_double_junk(rc, &config); pass &= test_err_load_schema_invalid_value_int_range_1(rc, &config); pass &= test_err_load_schema_invalid_value_int_range_2(rc, &config); 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_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); ttest_heading(rc, "YAML / schema mismatch: Test integer limits"); pass &= test_err_load_schema_invalid_value_int8_limit_neg(rc, &config); pass &= test_err_load_schema_invalid_value_int8_limit_pos(rc, &config); pass &= test_err_load_schema_invalid_value_int16_limit_neg(rc, &config); pass &= test_err_load_schema_invalid_value_int16_limit_pos(rc, &config); pass &= test_err_load_schema_invalid_value_int32_limit_neg(rc, &config); pass &= test_err_load_schema_invalid_value_int32_limit_pos(rc, &config); pass &= test_err_load_schema_invalid_value_int64_limit_neg(rc, &config); pass &= test_err_load_schema_invalid_value_int64_limit_pos(rc, &config); ttest_heading(rc, "YAML / schema mismatch: string lengths"); pass &= test_err_load_schema_string_min_length(rc, &config); pass &= test_err_load_schema_string_max_length(rc, &config); ttest_heading(rc, "YAML / schema mismatch: mapping fields"); pass &= test_err_load_schema_missing_mapping_field(rc, &config); pass &= test_err_load_schema_unknown_mapping_field(rc, &config); pass &= test_err_load_schema_duplicate_mapping_field(rc, &config); ttest_heading(rc, "YAML / schema mismatch: sequence counts"); pass &= test_err_load_schema_sequence_min_entries(rc, &config); pass &= test_err_load_schema_sequence_max_entries(rc, &config); ttest_heading(rc, "YAML / schema mismatch: bad flags/enum strings"); pass &= test_err_load_schema_flags_mapping(rc, &config); pass &= test_err_load_schema_enum_bad_string(rc, &config); pass &= test_err_load_schema_flags_bad_string(rc, &config); pass &= test_err_save_schema_strict_enum_bad_value(rc, &config); pass &= test_err_load_schema_strict_enum_bad_string(rc, &config); pass &= test_err_save_schema_strict_flags_bad_value(rc, &config); pass &= test_err_load_schema_strict_flags_bad_string(rc, &config); ttest_heading(rc, "YAML / schema mismatch: expected value type tests"); pass &= test_err_load_schema_expect_int_read_seq(rc, &config); pass &= test_err_load_schema_expect_int_read_end_1(rc, &config); pass &= test_err_load_schema_expect_int_read_end_2(rc, &config); pass &= test_err_load_schema_expect_flags_read_scalar(rc, &config); pass &= test_err_load_schema_expect_mapping_read_scalar(rc, &config); pass &= test_err_load_schema_expect_sequence_read_scalar(rc, &config); ttest_heading(rc, "Memory allocation handling tests"); pass &= test_err_load_log(rc, &config); pass &= test_err_free_null(rc, &config); pass &= test_err_load_alloc_oom_1(rc, &config); pass &= test_err_load_alloc_oom_2(rc, &config); pass &= test_err_save_alloc_oom_1(rc, &config); pass &= test_err_save_alloc_oom_2(rc, &config); ttest_heading(rc, "Alias tests"); pass &= test_err_load_invalid_alias(rc, &config); pass &= test_err_load_incomplete_alias(rc, &config); pass &= test_err_load_flag_value_alias(rc, &config); pass &= test_err_load_mapping_key_alias(rc, &config); pass &= test_err_load_mapping_value_alias_1(rc, &config); pass &= test_err_load_mapping_value_alias_2(rc, &config); pass &= test_err_load_mapping_value_alias_3(rc, &config); pass &= test_err_load_bitfield_value_alias_1(rc, &config); pass &= test_err_load_bitfield_value_alias_2(rc, &config); return pass; }