#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <check.h>
#include <libfyaml.h>
#include "fy-parse.h"
#include "fy-utf8.h"
START_TEST(parser_mapping_iterator)
{
struct fy_document *fyd;
struct fy_node_pair *fynp;
int count;
void *iter;
fyd = fy_document_build_from_string(NULL,
"{ foo: 10, bar: 20, baz: [100, 101], [frob, 1]: boo }", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
count = fy_node_mapping_item_count(fy_document_root(fyd));
ck_assert_int_eq(count, 4);
iter = NULL;
fynp = fy_node_mapping_iterate(fy_document_root(fyd), &iter);
ck_assert_ptr_ne(fynp, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fy_node_pair_key(fynp)), "foo");
ck_assert_str_eq(fy_node_get_scalar0(fy_node_pair_value(fynp)), "10");
fynp = fy_node_mapping_iterate(fy_document_root(fyd), &iter);
ck_assert_ptr_ne(fynp, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fy_node_pair_key(fynp)), "bar");
ck_assert_str_eq(fy_node_get_scalar0(fy_node_pair_value(fynp)), "20");
iter = NULL;
fynp = fy_node_mapping_reverse_iterate(fy_document_root(fyd), &iter);
ck_assert_ptr_ne(fynp, NULL);
fynp = fy_node_mapping_get_by_index(fy_document_root(fyd), 0);
ck_assert_ptr_ne(fynp, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fy_node_pair_key(fynp)), "foo");
ck_assert_str_eq(fy_node_get_scalar0(fy_node_pair_value(fynp)), "10");
fynp = fy_node_mapping_get_by_index(fy_document_root(fyd), 1);
ck_assert_ptr_ne(fynp, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fy_node_pair_key(fynp)), "bar");
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_mapping_key_lookup)
{
struct fy_document *fyd;
struct fy_node *fyn;
fyd = fy_document_build_from_string(NULL,
"{ foo: 10, bar: 20, baz: [100, 101], [frob, 1]: boo }", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_mapping_lookup_by_string(fy_document_root(fyd), "foo", FY_NT);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "10");
fyn = fy_node_mapping_lookup_by_string(fy_document_root(fyd), "bar", FY_NT);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "20");
fyn = fy_node_mapping_lookup_by_string(fy_document_root(fyd), "baz", FY_NT);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_sequence(fyn));
fyn = fy_node_mapping_lookup_by_string(fy_document_root(fyd), "[ frob, 1 ]", FY_NT);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "boo");
fyn = fy_node_mapping_lookup_by_string(fy_document_root(fyd), "nonexistent", FY_NT);
ck_assert_ptr_eq(fyn, NULL);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_path_queries)
{
struct fy_document *fyd;
struct fy_node *fyn;
fyd = fy_document_build_from_string(NULL,
"{ foo: 10, bar: 20, baz:{ frob: boo }, "
"frooz: [ seq1, { key: value} ], \"zero\\0zero\": 0, "
"{ key2: value2 }: { key3: value3 } }", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "/", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_mapping(fyn));
fyn = fy_node_by_path(fy_document_root(fyd), "foo", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "10");
fyn = fy_node_by_path(fy_document_root(fyd), "bar", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "20");
fyn = fy_node_by_path(fy_document_root(fyd), "baz/frob", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "boo");
fyn = fy_node_by_path(fy_document_root(fyd), "/frooz/[0]", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "seq1");
fyn = fy_node_by_path(fy_document_root(fyd), "/frooz/[1]/key", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "value");
fyn = fy_node_by_path(fy_document_root(fyd), "\"foo\"", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "10");
fyn = fy_node_by_path(fy_document_root(fyd), "\"zero\\0zero\"", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "0");
fyn = fy_node_by_path(fy_document_root(fyd), "/{ key2: value2 }", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_mapping(fyn));
fyn = fy_node_by_path(fy_document_root(fyd), "/{ key2: value2 }/key3", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "value3");
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_node_path_generation)
{
struct fy_document *fyd;
struct fy_node *fyn;
char *path;
fyd = fy_document_build_from_string(NULL,
"{ foo: 10, frooz: [ seq1, { key: value} ], "
"{ key2: value2 }: { key3: value3 } }", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "/", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
path = fy_node_get_path(fyn);
ck_assert_ptr_ne(path, NULL);
ck_assert_str_eq(path, "/");
free(path);
fyn = fy_node_by_path(fy_document_root(fyd), "/frooz", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
path = fy_node_get_path(fyn);
ck_assert_ptr_ne(path, NULL);
ck_assert_str_eq(path, "/frooz");
free(path);
fyn = fy_node_by_path(fy_document_root(fyd), "/frooz/[0]", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
path = fy_node_get_path(fyn);
ck_assert_ptr_ne(path, NULL);
ck_assert_str_eq(path, "/frooz/0");
free(path);
fyn = fy_node_by_path(fy_document_root(fyd), "/{ key2: value2 }/key3", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
path = fy_node_get_path(fyn);
ck_assert_ptr_ne(path, NULL);
ck_assert_ptr_ne(path, NULL);
free(path);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_node_creation_scalar)
{
struct fy_document *fyd;
struct fy_node *fyn;
char *buf;
fyd = fy_document_create(NULL);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_create_scalar(fyd, "foo", 3);
ck_assert_ptr_ne(fyn, NULL);
fy_document_set_root(fyd, fyn);
buf = fy_emit_document_to_string(fyd, FYECF_MODE_FLOW_ONELINE);
ck_assert_ptr_ne(buf, NULL);
ck_assert_str_eq(buf, "foo\n");
free(buf);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_node_creation_multiline_scalar)
{
struct fy_document *fyd;
struct fy_node *fyn;
char *buf;
fyd = fy_document_create(NULL);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_create_scalar(fyd, "foo\nfoo", 7);
ck_assert_ptr_ne(fyn, NULL);
fy_document_set_root(fyd, fyn);
buf = fy_emit_document_to_string(fyd, 0);
ck_assert_ptr_ne(buf, NULL);
ck_assert(strstr(buf, "foo") != NULL);
free(buf);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_node_creation_empty_sequence)
{
struct fy_document *fyd;
struct fy_node *fyn;
char *buf;
fyd = fy_document_create(NULL);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_create_sequence(fyd);
ck_assert_ptr_ne(fyn, NULL);
fy_document_set_root(fyd, fyn);
buf = fy_emit_document_to_string(fyd, FYECF_MODE_FLOW_ONELINE);
ck_assert_ptr_ne(buf, NULL);
ck_assert_str_eq(buf, "[]\n");
free(buf);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_node_creation_empty_mapping)
{
struct fy_document *fyd;
struct fy_node *fyn;
char *buf;
fyd = fy_document_create(NULL);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_create_mapping(fyd);
ck_assert_ptr_ne(fyn, NULL);
fy_document_set_root(fyd, fyn);
buf = fy_emit_document_to_string(fyd, FYECF_MODE_FLOW_ONELINE);
ck_assert_ptr_ne(buf, NULL);
ck_assert_str_eq(buf, "{}\n");
free(buf);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_node_creation_populated_sequence)
{
struct fy_document *fyd;
struct fy_node *fyn, *fyn_seq;
int ret;
fyd = fy_document_create(NULL);
ck_assert_ptr_ne(fyd, NULL);
fyn_seq = fy_node_create_sequence(fyd);
ck_assert_ptr_ne(fyn_seq, NULL);
fyn = fy_node_create_scalar(fyd, "foo", FY_NT);
ck_assert_ptr_ne(fyn, NULL);
ret = fy_node_sequence_append(fyn_seq, fyn);
ck_assert_int_eq(ret, 0);
fyn = fy_node_create_scalar(fyd, "bar", FY_NT);
ck_assert_ptr_ne(fyn, NULL);
ret = fy_node_sequence_append(fyn_seq, fyn);
ck_assert_int_eq(ret, 0);
fyn = fy_node_build_from_string(fyd, "{ baz: frooz }", FY_NT);
ck_assert_ptr_ne(fyn, NULL);
ret = fy_node_sequence_append(fyn_seq, fyn);
ck_assert_int_eq(ret, 0);
fy_document_set_root(fyd, fyn_seq);
ck_assert_int_eq(fy_node_sequence_item_count(fyn_seq), 3);
fyn = fy_node_sequence_get_by_index(fyn_seq, 0);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "foo");
fyn = fy_node_sequence_get_by_index(fyn_seq, 1);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "bar");
fyn = fy_node_sequence_get_by_index(fyn_seq, 2);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_mapping(fyn));
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_node_creation_populated_mapping)
{
struct fy_document *fyd;
struct fy_node *fyn, *fyn_key, *fyn_val, *fyn_map;
int ret;
fyd = fy_document_create(NULL);
ck_assert_ptr_ne(fyd, NULL);
fyn_map = fy_node_create_mapping(fyd);
ck_assert_ptr_ne(fyn_map, NULL);
fyn_key = fy_node_create_scalar(fyd, "foo", FY_NT);
ck_assert_ptr_ne(fyn_key, NULL);
fyn_val = fy_node_create_scalar(fyd, "10", FY_NT);
ck_assert_ptr_ne(fyn_val, NULL);
ret = fy_node_mapping_append(fyn_map, fyn_key, fyn_val);
ck_assert_int_eq(ret, 0);
fyn_key = fy_node_create_scalar(fyd, "bar", FY_NT);
ck_assert_ptr_ne(fyn_key, NULL);
fyn_val = fy_node_build_from_string(fyd, "[ 1, 2, 3 ]", FY_NT);
ck_assert_ptr_ne(fyn_val, NULL);
ret = fy_node_mapping_append(fyn_map, fyn_key, fyn_val);
ck_assert_int_eq(ret, 0);
fy_document_set_root(fyd, fyn_map);
ck_assert_int_eq(fy_node_mapping_item_count(fyn_map), 2);
fyn = fy_node_mapping_lookup_by_string(fyn_map, "foo", FY_NT);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "10");
fyn = fy_node_mapping_lookup_by_string(fyn_map, "bar", FY_NT);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_sequence(fyn));
ck_assert_int_eq(fy_node_sequence_item_count(fyn), 3);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_build_node_from_string)
{
struct fy_document *fyd;
struct fy_node *fyn;
char *buf;
fyd = fy_document_create(NULL);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_build_from_string(fyd, "{ }", FY_NT);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_mapping(fyn));
fy_document_set_root(fyd, fyn);
buf = fy_emit_document_to_string(fyd, FYECF_MODE_FLOW_ONELINE);
ck_assert_ptr_ne(buf, NULL);
ck_assert_str_eq(buf, "{}\n");
free(buf);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_sequence_negative_index)
{
struct fy_document *fyd;
struct fy_node *fyn;
fyd = fy_document_build_from_string(NULL, "[ first, second, third ]", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_sequence_get_by_index(fy_document_root(fyd), -1);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "third");
fyn = fy_node_sequence_get_by_index(fy_document_root(fyd), -2);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "second");
fyn = fy_node_sequence_get_by_index(fy_document_root(fyd), -3);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "first");
fyn = fy_node_sequence_get_by_index(fy_document_root(fyd), -4);
ck_assert_ptr_eq(fyn, NULL);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_complex_nested_structure)
{
struct fy_document *fyd;
struct fy_node *fyn;
int count;
fyd = fy_document_build_from_string(NULL,
"root:\n"
" level1:\n"
" level2:\n"
" - item1\n"
" - item2\n"
" - key: value\n"
" nested: data\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "root/level1/level2", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_sequence(fyn));
count = fy_node_sequence_item_count(fyn);
ck_assert_int_eq(count, 3);
fyn = fy_node_by_path(fy_document_root(fyd), "root/level1/level2/[0]", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "item1");
fyn = fy_node_by_path(fy_document_root(fyd), "root/level1/level2/[2]/nested", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "data");
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_anchor_alias_resolution)
{
struct fy_document *fyd;
struct fy_node *fyn;
char *buf;
int rc;
fyd = fy_document_build_from_string(NULL,
"base: &base\n"
" name: this-is-a-name\n"
" value: 42\n"
"copy: *base\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "copy", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_alias(fyn));
rc = fy_document_resolve(fyd);
ck_assert_int_eq(rc, 0);
fyn = fy_node_by_path(fy_document_root(fyd), "copy/name", FY_NT, FYNWF_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "this-is-a-name");
buf = fy_emit_document_to_string(fyd, FYECF_MODE_FLOW_ONELINE);
ck_assert_ptr_ne(buf, NULL);
free(buf);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_document_insert_at)
{
struct fy_document *fyd;
struct fy_node *fyn, *fyn_inserted;
int rc;
fyd = fy_document_build_from_string(NULL,
"base:\n"
" name: original\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_buildf(fyd, "new-key: inserted-value");
ck_assert_ptr_ne(fyn, NULL);
rc = fy_document_insert_at(fyd, "/base", FY_NT, fyn);
ck_assert_int_eq(rc, 0);
fyn_inserted = fy_node_by_path(fy_document_root(fyd), "/base/new-key", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn_inserted, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn_inserted), "inserted-value");
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_document_emit_flags)
{
struct fy_document *fyd;
char *buf;
fyd = fy_document_build_from_string(NULL,
"{ z: 1, a: 2, m: 3 }",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
buf = fy_emit_document_to_string(fyd, FYECF_MODE_FLOW_ONELINE);
ck_assert_ptr_ne(buf, NULL);
ck_assert(strstr(buf, "z") != NULL);
ck_assert(strstr(buf, "a") != NULL);
ck_assert(strstr(buf, "m") != NULL);
free(buf);
buf = fy_emit_document_to_string(fyd, FYECF_MODE_FLOW_ONELINE | FYECF_SORT_KEYS);
ck_assert_ptr_ne(buf, NULL);
ck_assert(strstr(buf, "a") < strstr(buf, "z"));
ck_assert(strstr(buf, "m") < strstr(buf, "z"));
free(buf);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_multi_document_stream)
{
struct fy_parser fyp_data, *fyp = &fyp_data;
struct fy_parse_cfg cfg = {
.flags = FYPCF_DEFAULT_DOC,
};
struct fy_document *fyd;
int count;
int rc;
rc = fy_parse_setup(fyp, &cfg);
ck_assert_int_eq(rc, 0);
const char *yaml_multi =
"---\n"
"doc: 1\n"
"---\n"
"doc: 2\n"
"---\n"
"doc: 3\n";
struct fy_input_cfg fyic = {
.type = fyit_memory,
.memory.data = yaml_multi,
.memory.size = strlen(yaml_multi),
};
rc = fy_parse_input_append(fyp, &fyic);
ck_assert_int_eq(rc, 0);
count = 0;
while ((fyd = fy_parse_load_document(fyp)) != NULL) {
count++;
struct fy_node *fyn = fy_node_by_path(fy_document_root(fyd), "doc", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
int doc_num = atoi(fy_node_get_scalar0(fyn));
ck_assert_int_eq(doc_num, count);
fy_parse_document_destroy(fyp, fyd);
}
ck_assert_int_eq(count, 3);
fy_parse_cleanup(fyp);
}
END_TEST
START_TEST(parser_empty_document)
{
struct fy_document *fyd;
char *buf;
fyd = fy_document_build_from_string(NULL, "null", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
ck_assert_ptr_ne(fy_document_root(fyd), NULL);
buf = fy_emit_document_to_string(fyd, 0);
ck_assert_ptr_ne(buf, NULL);
free(buf);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_document_with_comments)
{
struct fy_parse_cfg cfg = {
.flags = FYPCF_PARSE_COMMENTS,
};
struct fy_document *fyd;
fyd = fy_document_build_from_string(&cfg,
"# Top comment\n"
"key: value # Right comment\n"
"# Bottom comment\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
struct fy_node *fyn = fy_node_by_path(fy_document_root(fyd), "key", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "value");
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_sequence_append_prepend)
{
struct fy_document *fyd;
struct fy_node *fyn_seq, *fyn;
int rc;
fyd = fy_document_create(NULL);
ck_assert_ptr_ne(fyd, NULL);
fyn_seq = fy_node_create_sequence(fyd);
ck_assert_ptr_ne(fyn_seq, NULL);
fy_document_set_root(fyd, fyn_seq);
fyn = fy_node_create_scalar(fyd, "second", FY_NT);
rc = fy_node_sequence_append(fyn_seq, fyn);
ck_assert_int_eq(rc, 0);
fyn = fy_node_create_scalar(fyd, "first", FY_NT);
rc = fy_node_sequence_prepend(fyn_seq, fyn);
ck_assert_int_eq(rc, 0);
fyn = fy_node_create_scalar(fyd, "third", FY_NT);
rc = fy_node_sequence_append(fyn_seq, fyn);
ck_assert_int_eq(rc, 0);
fyn = fy_node_sequence_get_by_index(fyn_seq, 0);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "first");
fyn = fy_node_sequence_get_by_index(fyn_seq, 1);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "second");
fyn = fy_node_sequence_get_by_index(fyn_seq, 2);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "third");
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_mapping_prepend)
{
struct fy_document *fyd;
struct fy_node *fyn_map, *fyn_key, *fyn_val;
struct fy_node_pair *fynp;
int rc;
fyd = fy_document_create(NULL);
ck_assert_ptr_ne(fyd, NULL);
fyn_map = fy_node_create_mapping(fyd);
ck_assert_ptr_ne(fyn_map, NULL);
fy_document_set_root(fyd, fyn_map);
fyn_key = fy_node_create_scalar(fyd, "second", FY_NT);
fyn_val = fy_node_create_scalar(fyd, "2", FY_NT);
rc = fy_node_mapping_append(fyn_map, fyn_key, fyn_val);
ck_assert_int_eq(rc, 0);
fyn_key = fy_node_create_scalar(fyd, "first", FY_NT);
fyn_val = fy_node_create_scalar(fyd, "1", FY_NT);
rc = fy_node_mapping_prepend(fyn_map, fyn_key, fyn_val);
ck_assert_int_eq(rc, 0);
fynp = fy_node_mapping_get_by_index(fyn_map, 0);
ck_assert_ptr_ne(fynp, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fy_node_pair_key(fynp)), "first");
fynp = fy_node_mapping_get_by_index(fyn_map, 1);
ck_assert_ptr_ne(fynp, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fy_node_pair_key(fynp)), "second");
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_sequence_remove)
{
struct fy_document *fyd;
struct fy_node *fyn_seq, *fyn;
int count;
fyd = fy_document_build_from_string(NULL, "[ a, b, c, d ]", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn_seq = fy_document_root(fyd);
ck_assert_int_eq(fy_node_sequence_item_count(fyn_seq), 4);
fyn = fy_node_sequence_get_by_index(fyn_seq, 1);
ck_assert_ptr_ne(fyn, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "b");
fyn = fy_node_sequence_remove(fyn_seq, fyn);
ck_assert_ptr_ne(fyn, NULL);
fy_node_free(fyn);
count = fy_node_sequence_item_count(fyn_seq);
ck_assert_int_eq(count, 3);
fyn = fy_node_sequence_get_by_index(fyn_seq, 0);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "a");
fyn = fy_node_sequence_get_by_index(fyn_seq, 1);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "c");
fyn = fy_node_sequence_get_by_index(fyn_seq, 2);
ck_assert_str_eq(fy_node_get_scalar0(fyn), "d");
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_mapping_remove)
{
struct fy_document *fyd;
struct fy_node *fyn_map, *fyn_key, *fyn_val;
int count;
fyd = fy_document_build_from_string(NULL, "{ a: 1, b: 2, c: 3 }", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn_map = fy_document_root(fyd);
ck_assert_int_eq(fy_node_mapping_item_count(fyn_map), 3);
fyn_key = fy_node_build_from_string(fyd, "b", FY_NT);
ck_assert_ptr_ne(fyn_key, NULL);
fyn_val = fy_node_mapping_remove_by_key(fyn_map, fyn_key);
ck_assert_ptr_ne(fyn_val, NULL);
fy_node_free(fyn_val);
count = fy_node_mapping_item_count(fyn_map);
ck_assert_int_eq(count, 2);
fyn_val = fy_node_mapping_lookup_by_string(fyn_map, "b", FY_NT);
ck_assert_ptr_eq(fyn_val, NULL);
fyn_val = fy_node_mapping_lookup_by_string(fyn_map, "a", FY_NT);
ck_assert_ptr_ne(fyn_val, NULL);
fyn_val = fy_node_mapping_lookup_by_string(fyn_map, "c", FY_NT);
ck_assert_ptr_ne(fyn_val, NULL);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_document_iterator)
{
struct fy_document *fyd;
struct fy_document_iterator *fydi;
struct fy_node *fyn;
int count;
fyd = fy_document_build_from_string(NULL,
"root:\n"
" scalar: value\n"
" seq:\n"
" - item1\n"
" - item2\n"
" map:\n"
" key: val\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fydi = fy_document_iterator_create();
ck_assert_ptr_ne(fydi, NULL);
fy_document_iterator_node_start(fydi, fy_document_root(fyd));
count = 0;
while ((fyn = fy_document_iterator_node_next(fydi)) != NULL) {
count++;
if (fy_node_is_scalar(fyn)) {
const char *text;
size_t len;
text = fy_node_get_scalar(fyn, &len);
ck_assert_ptr_ne(text, NULL);
} else if (fy_node_is_sequence(fyn)) {
ck_assert(fy_node_is_sequence(fyn));
} else if (fy_node_is_mapping(fyn)) {
ck_assert(fy_node_is_mapping(fyn));
}
}
ck_assert_int_gt(count, 0);
fy_document_iterator_destroy(fydi);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_document_iterator_key_detection)
{
struct fy_document *fyd;
struct fy_document_iterator *fydi;
struct fy_node *fyn;
fyd = fy_document_build_from_string(NULL,
"key1: value1\n"
"key2: value2\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fydi = fy_document_iterator_create();
ck_assert_ptr_ne(fydi, NULL);
fy_document_iterator_node_start(fydi, fy_document_root(fyd));
fyn = fy_document_iterator_node_next(fydi);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_mapping(fyn));
ck_assert_ptr_eq(fyn, fy_document_root(fyd));
fyn = fy_document_iterator_node_next(fydi);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_scalar(fyn));
ck_assert(!strcmp(fy_node_get_scalar0(fyn), "key1"));
fyn = fy_document_iterator_node_next(fydi);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_scalar(fyn));
ck_assert(!strcmp(fy_node_get_scalar0(fyn), "value1"));
fyn = fy_document_iterator_node_next(fydi);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_scalar(fyn));
ck_assert(!strcmp(fy_node_get_scalar0(fyn), "key2"));
fyn = fy_document_iterator_node_next(fydi);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_scalar(fyn));
ck_assert(!strcmp(fy_node_get_scalar0(fyn), "value2"));
fyn = fy_document_iterator_node_next(fydi);
ck_assert_ptr_eq(fyn, NULL);
fy_document_iterator_destroy(fydi);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_comment_retrieval)
{
struct fy_parse_cfg cfg = {
.flags = FYPCF_PARSE_COMMENTS,
};
struct fy_document *fyd;
struct fy_document_iterator *fydi;
struct fy_node *fyn;
struct fy_token *fyt;
char buf[256];
bool found_comment = false;
fyd = fy_document_build_from_string(&cfg,
"# Top comment\n"
"scalar: value # Right comment\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fydi = fy_document_iterator_create();
ck_assert_ptr_ne(fydi, NULL);
fy_document_iterator_node_start(fydi, fy_document_root(fyd));
while ((fyn = fy_document_iterator_node_next(fydi)) != NULL) {
if (!fy_node_is_scalar(fyn))
continue;
fyt = fy_node_get_scalar_token(fyn);
if (!fyt || !fy_token_has_any_comment(fyt))
continue;
for (int placement = fycp_top; placement < fycp_max; placement++) {
if (fy_token_get_comment(fyt, buf, sizeof(buf), placement)) {
ck_assert_ptr_ne(buf, NULL);
ck_assert_int_gt(strlen(buf), 0);
found_comment = true;
}
}
}
ck_assert(found_comment);
fy_document_iterator_destroy(fydi);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_iterator_alias_detection)
{
struct fy_document *fyd;
struct fy_document_iterator *fydi;
struct fy_node *fyn;
bool found_alias = false;
fyd = fy_document_build_from_string(NULL,
"anchor: &ref value\n"
"alias: *ref\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fydi = fy_document_iterator_create();
ck_assert_ptr_ne(fydi, NULL);
fy_document_iterator_node_start(fydi, fy_document_root(fyd));
while ((fyn = fy_document_iterator_node_next(fydi)) != NULL) {
if (fy_node_is_scalar(fyn) && fy_node_is_alias(fyn)) {
found_alias = true;
}
}
ck_assert(found_alias);
fy_document_iterator_destroy(fydi);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_event_generation)
{
struct fy_parser fyp_data, *fyp = &fyp_data;
struct fy_parse_cfg cfg = {
.flags = FYPCF_DEFAULT_DOC,
};
struct fy_event *event;
int rc;
bool got_stream_start = false;
bool got_doc_start = false;
bool got_scalar = false;
bool got_doc_end = false;
bool got_stream_end = false;
rc = fy_parse_setup(fyp, &cfg);
ck_assert_int_eq(rc, 0);
const char *yaml = "key: value\n";
struct fy_input_cfg fyic = {
.type = fyit_memory,
.memory.data = yaml,
.memory.size = strlen(yaml),
};
rc = fy_parse_input_append(fyp, &fyic);
ck_assert_int_eq(rc, 0);
while ((event = fy_parser_parse(fyp)) != NULL) {
switch (event->type) {
case FYET_STREAM_START:
got_stream_start = true;
break;
case FYET_DOCUMENT_START:
got_doc_start = true;
break;
case FYET_SCALAR:
got_scalar = true;
break;
case FYET_DOCUMENT_END:
got_doc_end = true;
break;
case FYET_STREAM_END:
got_stream_end = true;
break;
default:
break;
}
fy_parser_event_free(fyp, event);
}
ck_assert(got_stream_start);
ck_assert(got_doc_start);
ck_assert(got_scalar);
ck_assert(got_doc_end);
ck_assert(got_stream_end);
fy_parse_cleanup(fyp);
}
END_TEST
START_TEST(parser_scalar_styles)
{
struct fy_document *fyd;
struct fy_node *fyn;
struct fy_token *fyt;
enum fy_scalar_style style;
fyd = fy_document_build_from_string(NULL,
"plain: plain value\n"
"single: 'single quoted'\n"
"double: \"double quoted\"\n"
"literal: |\n"
" literal block\n"
"folded: >\n"
" folded block\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "plain", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
fyt = fy_node_get_scalar_token(fyn);
ck_assert_ptr_ne(fyt, NULL);
style = fy_token_scalar_style(fyt);
ck_assert_int_eq(style, FYSS_PLAIN);
fyn = fy_node_by_path(fy_document_root(fyd), "single", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
fyt = fy_node_get_scalar_token(fyn);
ck_assert_ptr_ne(fyt, NULL);
style = fy_token_scalar_style(fyt);
ck_assert_int_eq(style, FYSS_SINGLE_QUOTED);
fyn = fy_node_by_path(fy_document_root(fyd), "double", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
fyt = fy_node_get_scalar_token(fyn);
ck_assert_ptr_ne(fyt, NULL);
style = fy_token_scalar_style(fyt);
ck_assert_int_eq(style, FYSS_DOUBLE_QUOTED);
fyn = fy_node_by_path(fy_document_root(fyd), "literal", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
fyt = fy_node_get_scalar_token(fyn);
ck_assert_ptr_ne(fyt, NULL);
style = fy_token_scalar_style(fyt);
ck_assert_int_eq(style, FYSS_LITERAL);
fyn = fy_node_by_path(fy_document_root(fyd), "folded", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
fyt = fy_node_get_scalar_token(fyn);
ck_assert_ptr_ne(fyt, NULL);
style = fy_token_scalar_style(fyt);
ck_assert_int_eq(style, FYSS_FOLDED);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_tag_handling)
{
struct fy_document *fyd;
struct fy_node *fyn;
const char *tag;
fyd = fy_document_build_from_string(NULL,
"string: !!str tagged string\n"
"integer: !!int 42\n"
"custom: !custom custom tag\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "string", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
tag = fy_node_get_tag0(fyn);
ck_assert_ptr_ne(tag, NULL);
ck_assert(strstr(tag, "str") != NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "integer", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
tag = fy_node_get_tag0(fyn);
ck_assert_ptr_ne(tag, NULL);
ck_assert(strstr(tag, "int") != NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "custom", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
tag = fy_node_get_tag0(fyn);
ck_assert_ptr_ne(tag, NULL);
ck_assert(strstr(tag, "custom") != NULL);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_yaml_version)
{
struct fy_parse_cfg cfg_11 = {
.flags = FYPCF_DEFAULT_VERSION_1_1,
};
struct fy_parse_cfg cfg_12 = {
.flags = FYPCF_DEFAULT_VERSION_1_2,
};
struct fy_document *fyd;
fyd = fy_document_build_from_string(&cfg_11, "key: value", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fy_document_destroy(fyd);
fyd = fy_document_build_from_string(&cfg_12, "key: value", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fy_document_destroy(fyd);
fyd = fy_document_build_from_string(NULL, "%YAML 1.2\n---\nkey: value", FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_flow_block_styles)
{
struct fy_document *fyd;
struct fy_node *fyn;
char *buf;
fyd = fy_document_build_from_string(NULL,
"block_map:\n"
" key: value\n"
"flow_map: {key: value}\n"
"block_seq:\n"
" - item\n"
"flow_seq: [item]\n",
FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "block_map", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_mapping(fyn));
fyn = fy_node_by_path(fy_document_root(fyd), "flow_map", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_mapping(fyn));
fyn = fy_node_by_path(fy_document_root(fyd), "block_seq", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_sequence(fyn));
fyn = fy_node_by_path(fy_document_root(fyd), "flow_seq", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_sequence(fyn));
buf = fy_emit_document_to_string(fyd, 0);
ck_assert_ptr_ne(buf, NULL);
free(buf);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_document_builder)
{
struct fy_document *fyd;
struct fy_node *fyn_root, *fyn_key, *fyn_val;
int rc;
fyd = fy_document_create(NULL);
ck_assert_ptr_ne(fyd, NULL);
fyn_root = fy_node_create_mapping(fyd);
ck_assert_ptr_ne(fyn_root, NULL);
fy_document_set_root(fyd, fyn_root);
fyn_key = fy_node_build_from_string(fyd, "key1", FY_NT);
ck_assert_ptr_ne(fyn_key, NULL);
fyn_val = fy_node_build_from_string(fyd, "value1", FY_NT);
ck_assert_ptr_ne(fyn_val, NULL);
rc = fy_node_mapping_append(fyn_root, fyn_key, fyn_val);
ck_assert_int_eq(rc, 0);
fyn_key = fy_node_build_from_string(fyd, "key2", FY_NT);
ck_assert_ptr_ne(fyn_key, NULL);
fyn_val = fy_node_build_from_string(fyd, "[1, 2, 3]", FY_NT);
ck_assert_ptr_ne(fyn_val, NULL);
rc = fy_node_mapping_append(fyn_root, fyn_key, fyn_val);
ck_assert_int_eq(rc, 0);
ck_assert_int_eq(fy_node_mapping_item_count(fyn_root), 2);
fyn_val = fy_node_mapping_lookup_by_string(fyn_root, "key1", FY_NT);
ck_assert_ptr_ne(fyn_val, NULL);
ck_assert_str_eq(fy_node_get_scalar0(fyn_val), "value1");
fyn_val = fy_node_mapping_lookup_by_string(fyn_root, "key2", FY_NT);
ck_assert_ptr_ne(fyn_val, NULL);
ck_assert(fy_node_is_sequence(fyn_val));
ck_assert_int_eq(fy_node_sequence_item_count(fyn_val), 3);
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_shell_split)
{
const char * const *argv;
int argc;
void *mem;
mem = fy_utf8_split_posix("arg1 arg2 arg3", &argc, &argv);
ck_assert_ptr_ne(mem, NULL);
ck_assert_int_eq(argc, 3);
ck_assert_str_eq(argv[0], "arg1");
ck_assert_str_eq(argv[1], "arg2");
ck_assert_str_eq(argv[2], "arg3");
ck_assert_ptr_eq(argv[argc], NULL);
free(mem);
mem = fy_utf8_split_posix("'single quoted' \"double quoted\"", &argc, &argv);
ck_assert_ptr_ne(mem, NULL);
ck_assert_int_eq(argc, 2);
ck_assert_str_eq(argv[0], "single quoted");
ck_assert_str_eq(argv[1], "double quoted");
ck_assert_ptr_eq(argv[argc], NULL);
free(mem);
mem = fy_utf8_split_posix("arg1\\ with\\ spaces arg2", &argc, &argv);
ck_assert_ptr_ne(mem, NULL);
ck_assert_int_eq(argc, 2);
ck_assert_str_eq(argv[0], "arg1 with spaces");
ck_assert_str_eq(argv[1], "arg2");
ck_assert_ptr_eq(argv[argc], NULL);
free(mem);
mem = fy_utf8_split_posix("", &argc, &argv);
ck_assert_ptr_ne(mem, NULL);
ck_assert_int_eq(argc, 0);
ck_assert_ptr_eq(argv[argc], NULL);
free(mem);
mem = fy_utf8_split_posix(" arg1 arg2 ", &argc, &argv);
ck_assert_ptr_ne(mem, NULL);
ck_assert_int_eq(argc, 2);
ck_assert_str_eq(argv[0], "arg1");
ck_assert_str_eq(argv[1], "arg2");
ck_assert_ptr_eq(argv[argc], NULL);
free(mem);
}
END_TEST
START_TEST(parser_utf8_validation)
{
const char *valid_ascii = "hello world";
const char *s, *e;
int c, w, pos;
s = valid_ascii;
e = s + strlen(valid_ascii);
pos = 0;
while (s < e) {
c = fy_utf8_get(s, e - s, &w);
ck_assert_int_ge(c, 0);
ck_assert_int_ge(w, 1);
ck_assert_int_le(w, 4);
s += w;
pos++;
}
ck_assert_int_eq(pos, 11);
const char *greek = "\xCE\xA4\xCE\xB9\xCE\xBC\xCE\xAE";
s = greek;
e = s + strlen(greek);
pos = 0;
while (s < e) {
c = fy_utf8_get(s, e - s, &w);
ck_assert_int_ge(c, 0);
ck_assert_int_eq(w, 2);
s += w;
pos++;
}
ck_assert_int_eq(pos, 4);
s = valid_ascii;
e = s + strlen(valid_ascii);
pos = 0;
while (s < e) {
c = fy_utf8_get_right(s, e - s, &w);
ck_assert_int_ge(c, 0);
ck_assert_int_ge(w, 1);
ck_assert_int_le(w, 4);
e -= w;
pos++;
}
ck_assert_int_eq(pos, 11);
const char invalid[] = { 0x67, 0xe7, 0x67, 0x00 };
s = invalid;
e = s + 3;
c = fy_utf8_get(s, 1, &w);
ck_assert_int_eq(c, 0x67);
ck_assert_int_eq(w, 1);
s += w;
c = fy_utf8_get(s, e - s, &w);
ck_assert_int_lt(c, 0);
c = fy_utf8_get(valid_ascii, 0, &w);
ck_assert_int_eq(c, FYUG_EOF);
ck_assert_int_eq(w, 0);
}
END_TEST
START_TEST(parser_token_scan_scalars)
{
struct fy_parser *fyp;
struct fy_parse_cfg cfg;
struct fy_token *fyt;
const char *yaml;
int token_count;
memset(&cfg, 0, sizeof(cfg));
cfg.flags = FYPCF_DEFAULT_PARSE;
yaml = "hello";
fyp = fy_parser_create(&cfg);
ck_assert_ptr_ne(fyp, NULL);
fy_parser_set_string(fyp, yaml, FY_NT);
token_count = 0;
while ((fyt = fy_scan(fyp)) != NULL) {
ck_assert_ptr_ne(fyt, NULL);
token_count++;
fy_token_unref(fyt);
}
ck_assert_int_gt(token_count, 0);
fy_parser_destroy(fyp);
yaml = "foo bar baz";
fyp = fy_parser_create(&cfg);
ck_assert_ptr_ne(fyp, NULL);
fy_parser_set_string(fyp, yaml, FY_NT);
token_count = 0;
while ((fyt = fy_scan(fyp)) != NULL) {
token_count++;
fy_token_unref(fyt);
}
ck_assert_int_gt(token_count, 0);
fy_parser_destroy(fyp);
}
END_TEST
START_TEST(parser_token_scan_mapping)
{
struct fy_parser *fyp;
struct fy_parse_cfg cfg;
struct fy_token *fyt;
const char *yaml;
int token_count;
memset(&cfg, 0, sizeof(cfg));
cfg.flags = FYPCF_DEFAULT_PARSE;
yaml = "key: value";
fyp = fy_parser_create(&cfg);
ck_assert_ptr_ne(fyp, NULL);
fy_parser_set_string(fyp, yaml, FY_NT);
token_count = 0;
while ((fyt = fy_scan(fyp)) != NULL) {
ck_assert_ptr_ne(fyt, NULL);
token_count++;
fy_token_unref(fyt);
}
ck_assert_int_gt(token_count, 5);
fy_parser_destroy(fyp);
yaml = "outer:\n inner: value";
fyp = fy_parser_create(&cfg);
ck_assert_ptr_ne(fyp, NULL);
fy_parser_set_string(fyp, yaml, FY_NT);
token_count = 0;
while ((fyt = fy_scan(fyp)) != NULL) {
token_count++;
fy_token_unref(fyt);
}
ck_assert_int_gt(token_count, 5);
fy_parser_destroy(fyp);
}
END_TEST
START_TEST(parser_token_scan_sequence)
{
struct fy_parser *fyp;
struct fy_parse_cfg cfg;
struct fy_token *fyt;
const char *yaml;
int token_count;
memset(&cfg, 0, sizeof(cfg));
cfg.flags = FYPCF_DEFAULT_PARSE;
yaml = "[1, 2, 3]";
fyp = fy_parser_create(&cfg);
ck_assert_ptr_ne(fyp, NULL);
fy_parser_set_string(fyp, yaml, FY_NT);
token_count = 0;
while ((fyt = fy_scan(fyp)) != NULL) {
token_count++;
fy_token_unref(fyt);
}
ck_assert_int_gt(token_count, 5);
fy_parser_destroy(fyp);
yaml = "- item1\n- item2\n- item3";
fyp = fy_parser_create(&cfg);
ck_assert_ptr_ne(fyp, NULL);
fy_parser_set_string(fyp, yaml, FY_NT);
token_count = 0;
while ((fyt = fy_scan(fyp)) != NULL) {
token_count++;
fy_token_unref(fyt);
}
ck_assert_int_gt(token_count, 5);
fy_parser_destroy(fyp);
}
END_TEST
START_TEST(parser_token_scan_scalar_styles)
{
struct fy_parser *fyp;
struct fy_parse_cfg cfg;
struct fy_token *fyt;
const char *yaml;
int scalar_count;
enum fy_scalar_style style;
memset(&cfg, 0, sizeof(cfg));
cfg.flags = FYPCF_DEFAULT_PARSE;
yaml = "plain: value\n"
"single: 'quoted value'\n"
"double: \"quoted value\"\n";
fyp = fy_parser_create(&cfg);
ck_assert_ptr_ne(fyp, NULL);
fy_parser_set_string(fyp, yaml, FY_NT);
scalar_count = 0;
while ((fyt = fy_scan(fyp)) != NULL) {
if (fyt->type == FYTT_SCALAR) {
style = fy_token_scalar_style(fyt);
ck_assert(style == FYSS_PLAIN ||
style == FYSS_SINGLE_QUOTED ||
style == FYSS_DOUBLE_QUOTED ||
style == FYSS_LITERAL ||
style == FYSS_FOLDED);
scalar_count++;
}
fy_token_unref(fyt);
}
ck_assert_int_ge(scalar_count, 6);
fy_parser_destroy(fyp);
}
END_TEST
START_TEST(parser_manual_emitter)
{
struct fy_emitter_cfg ecfg;
struct fy_emitter *emit;
memset(&ecfg, 0, sizeof(ecfg));
ecfg.flags = FYECF_MODE_MANUAL;
emit = fy_emitter_create(&ecfg);
ck_assert_ptr_ne(emit, NULL);
fy_emit_event(emit, fy_emit_event_create(emit, FYET_STREAM_START));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_DOCUMENT_START, false, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_MAPPING_START, FYNS_BLOCK, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_SCALAR, FYSS_PLAIN, "key", FY_NT, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_SEQUENCE_START, FYNS_BLOCK, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_MAPPING_START, FYNS_BLOCK, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_SCALAR, FYSS_PLAIN, "a", FY_NT, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_SCALAR, FYSS_PLAIN, "1", FY_NT, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_MAPPING_END));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_SEQUENCE_END));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_MAPPING_END));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_DOCUMENT_END, true, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_STREAM_END));
fy_emitter_destroy(emit);
emit = fy_emitter_create(&ecfg);
ck_assert_ptr_ne(emit, NULL);
fy_emit_event(emit, fy_emit_event_create(emit, FYET_STREAM_START));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_DOCUMENT_START, false, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_MAPPING_START, FYNS_FLOW, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_SCALAR, FYSS_PLAIN, "key", FY_NT, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_SEQUENCE_START, FYNS_FLOW, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_MAPPING_START, FYNS_FLOW, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_SCALAR, FYSS_PLAIN, "a", FY_NT, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_SCALAR, FYSS_PLAIN, "1", FY_NT, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_MAPPING_END));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_SEQUENCE_END));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_MAPPING_END));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_DOCUMENT_END, true, NULL, NULL));
fy_emit_event(emit, fy_emit_event_create(emit, FYET_STREAM_END));
fy_emitter_destroy(emit);
}
END_TEST
START_TEST(parser_parse_load_document)
{
struct fy_parse_cfg cfg;
struct fy_parser *fyp;
struct fy_document *fyd;
const char *yaml = "---\nfoo: bar\n---\nbaz: qux\n";
int count;
memset(&cfg, 0, sizeof(cfg));
cfg.flags = FYPCF_DEFAULT_PARSE;
fyp = fy_parser_create(&cfg);
ck_assert_ptr_ne(fyp, NULL);
fy_parser_set_string(fyp, yaml, FY_NT);
count = 0;
while ((fyd = fy_parse_load_document(fyp)) != NULL) {
const char *value;
struct fy_node *fyn;
count++;
if (count == 1) {
fyn = fy_node_by_path(fy_document_root(fyd), "/foo", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
value = fy_node_get_scalar0(fyn);
ck_assert_str_eq(value, "bar");
} else if (count == 2) {
fyn = fy_node_by_path(fy_document_root(fyd), "/baz", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
value = fy_node_get_scalar0(fyn);
ck_assert_str_eq(value, "qux");
}
fy_parse_document_destroy(fyp, fyd);
}
ck_assert_int_eq(count, 2);
fy_parser_destroy(fyp);
}
END_TEST
START_TEST(parser_document_resolve)
{
struct fy_document *fyd;
struct fy_node *fyn;
const char *yaml = "anchor: &data\n key: value\nref: *data\n";
const char *val;
int rc;
fyd = fy_document_build_from_string(NULL, yaml, FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "/ref", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(fy_node_is_alias(fyn));
rc = fy_document_resolve(fyd);
ck_assert_int_eq(rc, 0);
fyn = fy_node_by_path(fy_document_root(fyd), "/anchor/key", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
val = fy_node_get_scalar0(fyn);
ck_assert_str_eq(val, "value");
fyn = fy_node_by_path(fy_document_root(fyd), "/ref/key", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
val = fy_node_get_scalar0(fyn);
ck_assert_str_eq(val, "value");
fyn = fy_node_by_path(fy_document_root(fyd), "/ref", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
ck_assert(!fy_node_is_alias(fyn));
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_document_clone)
{
struct fy_document *fyd, *fyd_clone;
struct fy_node *fyn, *fyn_clone;
const char *yaml = "foo: bar\nbaz: [1, 2, 3]\n";
const char *val1, *val2;
fyd = fy_document_build_from_string(NULL, yaml, FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyd_clone = fy_document_clone(fyd);
ck_assert_ptr_ne(fyd_clone, NULL);
fyn = fy_node_by_path(fy_document_root(fyd), "/foo", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
val1 = fy_node_get_scalar0(fyn);
ck_assert_str_eq(val1, "bar");
fyn_clone = fy_node_by_path(fy_document_root(fyd_clone), "/foo", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn_clone, NULL);
val2 = fy_node_get_scalar0(fyn_clone);
ck_assert_str_eq(val2, "bar");
ck_assert_ptr_ne(fyn, fyn_clone);
fy_document_destroy(fyd);
fy_document_destroy(fyd_clone);
}
END_TEST
START_TEST(parser_node_copy)
{
struct fy_document *fyd;
struct fy_node *fyn_src, *fyn_copy, *fyn_root;
const char *yaml = "original: {key: value}\n";
const char *val;
fyd = fy_document_build_from_string(NULL, yaml, FY_NT);
ck_assert_ptr_ne(fyd, NULL);
fyn_src = fy_node_by_path(fy_document_root(fyd), "/original", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn_src, NULL);
fyn_copy = fy_node_copy(fyd, fyn_src);
ck_assert_ptr_ne(fyn_copy, NULL);
fyn_root = fy_node_by_path(fyn_copy, "/key", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn_root, NULL);
val = fy_node_get_scalar0(fyn_root);
ck_assert_str_eq(val, "value");
fy_node_mapping_append(fy_document_root(fyd),
fy_node_build_from_string(fyd, "copied", FY_NT),
fyn_copy);
fyn_root = fy_node_by_path(fy_document_root(fyd), "/copied/key", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn_root, NULL);
val = fy_node_get_scalar0(fyn_root);
ck_assert_str_eq(val, "value");
fy_document_destroy(fyd);
}
END_TEST
START_TEST(parser_document_builder_load)
{
struct fy_parse_cfg parse_cfg;
struct fy_document_builder_cfg builder_cfg;
struct fy_parser *fyp;
struct fy_document_builder *fydb;
struct fy_document *fyd;
const char *yaml = "---\nkey: value\n---\nfoo: bar\n";
int count;
memset(&parse_cfg, 0, sizeof(parse_cfg));
parse_cfg.flags = FYPCF_DEFAULT_PARSE;
memset(&builder_cfg, 0, sizeof(builder_cfg));
builder_cfg.parse_cfg = parse_cfg;
fyp = fy_parser_create(&parse_cfg);
ck_assert_ptr_ne(fyp, NULL);
fy_parser_set_string(fyp, yaml, FY_NT);
fydb = fy_document_builder_create(&builder_cfg);
ck_assert_ptr_ne(fydb, NULL);
count = 0;
while ((fyd = fy_document_builder_load_document(fydb, fyp)) != NULL) {
const char *value;
struct fy_node *fyn;
count++;
if (count == 1) {
fyn = fy_node_by_path(fy_document_root(fyd), "/key", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
value = fy_node_get_scalar0(fyn);
ck_assert_str_eq(value, "value");
} else if (count == 2) {
fyn = fy_node_by_path(fy_document_root(fyd), "/foo", FY_NT, FYNWF_DONT_FOLLOW);
ck_assert_ptr_ne(fyn, NULL);
value = fy_node_get_scalar0(fyn);
ck_assert_str_eq(value, "bar");
}
fy_document_destroy(fyd);
}
ck_assert_int_eq(count, 2);
fy_document_builder_destroy(fydb);
fy_parser_destroy(fyp);
}
END_TEST
struct compose_record {
enum fy_event_type type;
char path[128];
int depth;
char scalar_value[64];
};
struct compose_test_data {
struct compose_record records[100];
int record_count;
};
static enum fy_composer_return
compose_test_callback(struct fy_parser *fyp, struct fy_event *fye,
struct fy_path *path, void *userdata)
{
struct compose_test_data *data = userdata;
struct compose_record *rec;
char *path_text;
const char *scalar;
size_t len;
if (data->record_count >= 100)
return FYCR_OK_CONTINUE;
rec = &data->records[data->record_count++];
rec->type = fye->type;
rec->depth = fy_path_depth(path);
path_text = fy_path_get_text(path);
if (path_text) {
snprintf(rec->path, sizeof(rec->path), "%s", path_text);
free(path_text);
} else {
rec->path[0] = '\0';
}
rec->scalar_value[0] = '\0';
if (fye->type == FYET_SCALAR && fye->scalar.value) {
scalar = fy_token_get_text(fye->scalar.value, &len);
if (scalar && len < sizeof(rec->scalar_value) - 1) {
memcpy(rec->scalar_value, scalar, len);
rec->scalar_value[len] = '\0';
}
}
return FYCR_OK_CONTINUE;
}
START_TEST(parser_compose_callback)
{
struct fy_parse_cfg cfg;
struct fy_parser *fyp;
struct compose_test_data data;
const char *yaml =
"invoice: 34843\n"
"date : !!str 2001-01-23\n"
"bill-to: &id001\n"
" given : Chris\n"
" family : Dumars\n"
" address:\n"
" lines: |\n"
" 458 Walkman Dr.\n"
" Suite #292\n";
int rc;
int i;
bool found_invoice_key = false;
bool found_invoice_value = false;
bool found_bill_to_path = false;
memset(&cfg, 0, sizeof(cfg));
cfg.flags = FYPCF_DEFAULT_PARSE;
fyp = fy_parser_create(&cfg);
ck_assert_ptr_ne(fyp, NULL);
fy_parser_set_string(fyp, yaml, FY_NT);
memset(&data, 0, sizeof(data));
rc = fy_parse_compose(fyp, compose_test_callback, &data);
ck_assert_int_eq(rc, 0);
ck_assert(data.record_count > 0);
for (i = 0; i < data.record_count; i++) {
struct compose_record *rec = &data.records[i];
if (rec->type == FYET_SCALAR && strcmp(rec->scalar_value, "invoice") == 0) {
found_invoice_key = true;
ck_assert(strstr(rec->path, "invoice") != NULL || strcmp(rec->path, "/") == 0);
}
if (rec->type == FYET_SCALAR && strcmp(rec->scalar_value, "34843") == 0) {
found_invoice_value = true;
}
if (rec->type == FYET_MAPPING_START && strstr(rec->path, "bill-to") != NULL) {
found_bill_to_path = true;
ck_assert(rec->depth > 0);
}
}
ck_assert(found_invoice_key);
ck_assert(found_invoice_value);
ck_assert(found_bill_to_path);
ck_assert_int_eq(data.records[0].type, FYET_STREAM_START);
ck_assert_int_eq(data.records[data.record_count - 1].type, FYET_STREAM_END);
fy_parser_destroy(fyp);
}
END_TEST
TCase *libfyaml_case_parser(void)
{
TCase *tc;
tc = tcase_create("parser");
tcase_add_test(tc, parser_mapping_iterator);
tcase_add_test(tc, parser_mapping_key_lookup);
tcase_add_test(tc, parser_mapping_prepend);
tcase_add_test(tc, parser_mapping_remove);
tcase_add_test(tc, parser_path_queries);
tcase_add_test(tc, parser_node_path_generation);
tcase_add_test(tc, parser_node_creation_scalar);
tcase_add_test(tc, parser_node_creation_multiline_scalar);
tcase_add_test(tc, parser_node_creation_empty_sequence);
tcase_add_test(tc, parser_node_creation_empty_mapping);
tcase_add_test(tc, parser_node_creation_populated_sequence);
tcase_add_test(tc, parser_node_creation_populated_mapping);
tcase_add_test(tc, parser_build_node_from_string);
tcase_add_test(tc, parser_sequence_negative_index);
tcase_add_test(tc, parser_sequence_append_prepend);
tcase_add_test(tc, parser_sequence_remove);
tcase_add_test(tc, parser_complex_nested_structure);
tcase_add_test(tc, parser_anchor_alias_resolution);
tcase_add_test(tc, parser_document_insert_at);
tcase_add_test(tc, parser_document_emit_flags);
tcase_add_test(tc, parser_multi_document_stream);
tcase_add_test(tc, parser_empty_document);
tcase_add_test(tc, parser_document_with_comments);
tcase_add_test(tc, parser_document_iterator);
tcase_add_test(tc, parser_document_iterator_key_detection);
tcase_add_test(tc, parser_iterator_alias_detection);
tcase_add_test(tc, parser_comment_retrieval);
tcase_add_test(tc, parser_event_generation);
tcase_add_test(tc, parser_scalar_styles);
tcase_add_test(tc, parser_tag_handling);
tcase_add_test(tc, parser_yaml_version);
tcase_add_test(tc, parser_flow_block_styles);
tcase_add_test(tc, parser_document_builder);
tcase_add_test(tc, parser_shell_split);
tcase_add_test(tc, parser_utf8_validation);
tcase_add_test(tc, parser_token_scan_scalars);
tcase_add_test(tc, parser_token_scan_mapping);
tcase_add_test(tc, parser_token_scan_sequence);
tcase_add_test(tc, parser_token_scan_scalar_styles);
tcase_add_test(tc, parser_manual_emitter);
tcase_add_test(tc, parser_parse_load_document);
tcase_add_test(tc, parser_document_resolve);
tcase_add_test(tc, parser_document_clone);
tcase_add_test(tc, parser_node_copy);
tcase_add_test(tc, parser_document_builder_load);
tcase_add_test(tc, parser_compose_callback);
return tc;
}