Template
feat(kdl): add typed KDL value model
This commit is contained in:
@@ -0,0 +1,632 @@
|
||||
/* LINK: ../../src/kdl/value.c ../../src/kdl/parser.c ../../src/kdl/lexer.c ../../src/error.c ../../src/span.c */
|
||||
/* tests/unit/test_value.c
|
||||
*
|
||||
* Unit tests for the typed KDL value model (todo 8).
|
||||
*
|
||||
* The magic LINK comment on line 1 is REQUIRED by tests/run.sh: it lists the
|
||||
* extra .c sources to compile into this test binary (paths relative to
|
||||
* tests/unit/, space-separated). value.c depends on error.c (typed errors) and
|
||||
* span.c (caret rendering); parser.c + lexer.c are linked so the value-level
|
||||
* type-annotation integration can be tested END-TO-END through the parser.
|
||||
*
|
||||
* Most value-model cases are exercised by constructing a token ref DIRECTLY
|
||||
* (mkref), which bypasses the lexer's already-strict escape/radix validation
|
||||
* and lets us probe the value model's own boundary handling (unknown escapes,
|
||||
* `0xZZ`, overflow, i128 width) that the lexer would otherwise reject first.
|
||||
* Assertions check CONCRETE parsed values (kind + payload + annotation), never
|
||||
* just "does not crash".
|
||||
*/
|
||||
#include "munit.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "kdl/ast.h"
|
||||
#include "kdl/lexer.h"
|
||||
#include "kdl/value.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ---- token-ref construction ------------------------------------------- */
|
||||
|
||||
/* Build a borrowed token ref over a NUL-terminated C string (the string
|
||||
* literal outlives the value call, so the borrow is safe). */
|
||||
static struct st_kdl_token_ref
|
||||
mkref(enum st_token_kind kind, const char *text)
|
||||
{
|
||||
struct st_kdl_token_ref r;
|
||||
|
||||
r.kind = kind;
|
||||
r.span.file = "test.kdl";
|
||||
r.span.line = 1;
|
||||
r.span.col = 1;
|
||||
r.text = text;
|
||||
r.len = strlen(text);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Parse a value token directly (no annotation); assert success and return
|
||||
* the value. munit's longjmp aborts the test on assertion failure. */
|
||||
static struct st_kdl_value
|
||||
ok_value(enum st_token_kind kind, const char *text)
|
||||
{
|
||||
struct st_kdl_token_ref r = mkref(kind, text);
|
||||
struct st_kdl_value v;
|
||||
struct st_error *err = st_kdl_value_from_token(&r, &v);
|
||||
|
||||
munit_assert_null(err);
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Parse a value token with an explicit type-annotation ref; assert success. */
|
||||
static struct st_kdl_value
|
||||
ok_annotated(enum st_token_kind kind, const char *text, const char *ann)
|
||||
{
|
||||
struct st_kdl_token_ref r = mkref(kind, text);
|
||||
struct st_kdl_token_ref a = mkref(ST_TOK_TYPE, ann);
|
||||
struct st_kdl_value v;
|
||||
struct st_error *err = st_kdl_value_from_token_annotated(&r, &a, &v);
|
||||
|
||||
munit_assert_null(err);
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Assert that parsing `text` (kind) fails with category KDL_PARSE and a
|
||||
* message containing `needle`. */
|
||||
static void
|
||||
expect_error(enum st_token_kind kind, const char *text, const char *needle)
|
||||
{
|
||||
struct st_kdl_token_ref r = mkref(kind, text);
|
||||
struct st_kdl_value v;
|
||||
struct st_error *err = st_kdl_value_from_token(&r, &v);
|
||||
|
||||
munit_assert_not_null(err);
|
||||
munit_assert_int(st_error_category_of(err), ==, ST_ERR_KDL_PARSE);
|
||||
munit_assert_not_null(err->span);
|
||||
munit_assert_true(strstr(st_error_message(err), needle) != NULL);
|
||||
st_error_free(err);
|
||||
}
|
||||
|
||||
/* ---- number tests ------------------------------------------------------ */
|
||||
|
||||
static MunitResult
|
||||
test_radix_ints(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
|
||||
v = ok_value(ST_TOK_NUMBER, "0xff");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_INT);
|
||||
munit_assert_llong(v.as.i, ==, 255);
|
||||
|
||||
v = ok_value(ST_TOK_NUMBER, "0o17");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_INT);
|
||||
munit_assert_llong(v.as.i, ==, 15);
|
||||
|
||||
v = ok_value(ST_TOK_NUMBER, "0b101");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_INT);
|
||||
munit_assert_llong(v.as.i, ==, 5);
|
||||
|
||||
st_kdl_value_free(&v);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_decimal_and_sign(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
|
||||
v = ok_value(ST_TOK_NUMBER, "42");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_INT);
|
||||
munit_assert_llong(v.as.i, ==, 42);
|
||||
|
||||
v = ok_value(ST_TOK_NUMBER, "-42");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_INT);
|
||||
munit_assert_llong(v.as.i, ==, -42);
|
||||
|
||||
v = ok_value(ST_TOK_NUMBER, "+7");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_INT);
|
||||
munit_assert_llong(v.as.i, ==, 7);
|
||||
|
||||
v = ok_value(ST_TOK_NUMBER, "1_000");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_INT);
|
||||
munit_assert_llong(v.as.i, ==, 1000);
|
||||
|
||||
st_kdl_value_free(&v);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_floats(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
|
||||
v = ok_value(ST_TOK_NUMBER, "1.5");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_FLOAT);
|
||||
munit_assert_double_equal(v.as.f, 1.5, 12);
|
||||
|
||||
/* trailing dot, no fraction digits (direct ref: the lexer splits this) */
|
||||
v = ok_value(ST_TOK_NUMBER, "3.");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_FLOAT);
|
||||
munit_assert_double_equal(v.as.f, 3.0, 12);
|
||||
|
||||
st_kdl_value_free(&v);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_exponents(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
|
||||
v = ok_value(ST_TOK_NUMBER, "1e10");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_FLOAT);
|
||||
munit_assert_double_equal(v.as.f, 1e10, 12);
|
||||
|
||||
v = ok_value(ST_TOK_NUMBER, "2.5e-3");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_FLOAT);
|
||||
munit_assert_double_equal(v.as.f, 2.5e-3, 12);
|
||||
|
||||
st_kdl_value_free(&v);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_keyword_numbers(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
|
||||
v = ok_value(ST_TOK_INF, "#inf");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_FLOAT);
|
||||
munit_assert_true(isinf(v.as.f));
|
||||
munit_assert_true(v.as.f > 0);
|
||||
|
||||
v = ok_value(ST_TOK_NEG_INF, "#-inf");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_FLOAT);
|
||||
munit_assert_true(isinf(v.as.f));
|
||||
munit_assert_true(v.as.f < 0);
|
||||
|
||||
v = ok_value(ST_TOK_NAN, "#nan");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_FLOAT);
|
||||
munit_assert_true(isnan(v.as.f));
|
||||
|
||||
st_kdl_value_free(&v);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_bool_null(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
|
||||
v = ok_value(ST_TOK_TRUE, "#true");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_BOOL);
|
||||
munit_assert_true(v.as.b);
|
||||
|
||||
v = ok_value(ST_TOK_FALSE, "#false");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_BOOL);
|
||||
munit_assert_false(v.as.b);
|
||||
|
||||
v = ok_value(ST_TOK_NULL, "#null");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_NULL);
|
||||
|
||||
st_kdl_value_free(&v);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
/* ---- string tests ------------------------------------------------------ */
|
||||
|
||||
static MunitResult
|
||||
test_ident_and_quoted(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
|
||||
v = ok_value(ST_TOK_IDENT, "foo");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_STRING);
|
||||
munit_assert_string_equal(v.as.str, "foo");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
v = ok_value(ST_TOK_STRING, "\"hello\"");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_STRING);
|
||||
munit_assert_string_equal(v.as.str, "hello");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
/* empty quoted string */
|
||||
v = ok_value(ST_TOK_STRING, "\"\"");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_STRING);
|
||||
munit_assert_string_equal(v.as.str, "");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_escapes(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
|
||||
/* "a\nb" -> a, newline, b */
|
||||
v = ok_value(ST_TOK_STRING, "\"a\\nb\"");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_STRING);
|
||||
munit_assert_string_equal(v.as.str, "a\nb");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
/* backslash + quote + tab + carriage return */
|
||||
v = ok_value(ST_TOK_STRING, "\"\\\\\\\"\\t\\r\"");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_STRING);
|
||||
munit_assert_string_equal(v.as.str, "\\\"\t\r");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
/* space escape \s */
|
||||
v = ok_value(ST_TOK_STRING, "\"a\\sb\"");
|
||||
munit_assert_string_equal(v.as.str, "a b");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
/* backspace + form feed + vertical tab + bell + apostrophe (lenient) */
|
||||
v = ok_value(ST_TOK_STRING, "\"\\b\\f\\v\\a\\'\"");
|
||||
munit_assert_string_equal(v.as.str, "\b\f\v\a'");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
/* hex byte \x41 -> 'A' */
|
||||
v = ok_value(ST_TOK_STRING, "\"\\x41\"");
|
||||
munit_assert_string_equal(v.as.str, "A");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
/* unicode \u{1F600} -> U+1F600 (UTF-8 F0 9F 98 80) */
|
||||
v = ok_value(ST_TOK_STRING, "\"\\u{1F600}\"");
|
||||
munit_assert_string_equal(v.as.str, "\xF0\x9F\x98\x80");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
/* \u{10FFFF} is the maximum Unicode scalar value (UTF-8 F4 8F BF BF) */
|
||||
v = ok_value(ST_TOK_STRING, "\"\\u{10FFFF}\"");
|
||||
munit_assert_string_equal(v.as.str, "\xF4\x8F\xBF\xBF");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
/* whitespace escape: backslash + spaces + newline -> nothing */
|
||||
v = ok_value(ST_TOK_STRING, "\"Hello \\ World\"");
|
||||
munit_assert_string_equal(v.as.str, "Hello World");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_raw_string(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
|
||||
/* #"raw\n"# -> literal backslash-n (no escape processing) */
|
||||
v = ok_value(ST_TOK_RAW_STRING, "#\"raw\\n\"#");
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_STRING);
|
||||
munit_assert_string_equal(v.as.str, "raw\\n");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_multiline_dedent(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
const char *ml = "\"\"\"\n foo\n bar\n \"\"\"";
|
||||
|
||||
v = ok_value(ST_TOK_MULTILINE_STRING, ml);
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_STRING);
|
||||
munit_assert_string_equal(v.as.str, "foo\nbar");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
/* no trailing newline issues: an empty multi-line string */
|
||||
v = ok_value(ST_TOK_MULTILINE_STRING, "\"\"\"\n \"\"\"");
|
||||
munit_assert_string_equal(v.as.str, "");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_multiline_escaped_newline(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v;
|
||||
/* interior \n escape stays a newline (not dedented away) */
|
||||
const char *ml = "\"\"\"\n a\\nb\n \"\"\"";
|
||||
|
||||
v = ok_value(ST_TOK_MULTILINE_STRING, ml);
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_STRING);
|
||||
munit_assert_string_equal(v.as.str, "a\nb");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
/* ---- error tests ------------------------------------------------------- */
|
||||
|
||||
static MunitResult
|
||||
test_unknown_escape(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
|
||||
/* '\q' is not a KDL escape (direct ref; the lexer would reject it) */
|
||||
expect_error(ST_TOK_STRING, "\"a\\qb\"", "unknown escape");
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_unterminated_escape(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
|
||||
/* lone trailing backslash inside the quotes ("abc\" -> body "abc\") */
|
||||
expect_error(ST_TOK_STRING, "\"abc\\\"", "unterminated");
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_bad_radix(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
|
||||
expect_error(ST_TOK_NUMBER, "0xZZ", "invalid digit");
|
||||
expect_error(ST_TOK_NUMBER, "0o8", "invalid digit");
|
||||
expect_error(ST_TOK_NUMBER, "0b2", "invalid digit");
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_integer_overflow(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
|
||||
/* 24 digits, far beyond u64 (and i64) */
|
||||
expect_error(ST_TOK_NUMBER, "999999999999999999999999", "overflow");
|
||||
|
||||
/* 2^63 as an unannotated (signed) literal is one past i64 max */
|
||||
expect_error(ST_TOK_NUMBER, "9223372036854775808", "overflow");
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
/* ---- annotation tests -------------------------------------------------- */
|
||||
|
||||
static MunitResult
|
||||
test_unicode_out_of_range(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
|
||||
/* above the scalar-value range */
|
||||
expect_error(ST_TOK_STRING, "\"\\u{110000}\"", "Unicode scalar");
|
||||
/* a UTF-16 surrogate is not a scalar value */
|
||||
expect_error(ST_TOK_STRING, "\"\\u{D800}\"", "Unicode scalar");
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_annotation_u8(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_value v = ok_annotated(ST_TOK_NUMBER, "42", "u8");
|
||||
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_UINT);
|
||||
munit_assert_ullong(v.as.u, ==, 42);
|
||||
munit_assert_not_null(v.annotation);
|
||||
munit_assert_string_equal(v.annotation, "u8");
|
||||
|
||||
st_kdl_value_free(&v);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_annotation_unsigned_rejects_negative(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_token_ref r = mkref(ST_TOK_NUMBER, "-1");
|
||||
struct st_kdl_token_ref a = mkref(ST_TOK_TYPE, "u8");
|
||||
struct st_kdl_value v;
|
||||
struct st_error *err = st_kdl_value_from_token_annotated(&r, &a, &v);
|
||||
|
||||
munit_assert_not_null(err);
|
||||
munit_assert_true(strstr(st_error_message(err), "unsigned") != NULL);
|
||||
st_error_free(err);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_annotation_unsupported_width(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_kdl_token_ref r = mkref(ST_TOK_NUMBER, "42");
|
||||
struct st_kdl_token_ref a128 = mkref(ST_TOK_TYPE, "i128");
|
||||
struct st_kdl_token_ref u128 = mkref(ST_TOK_TYPE, "u128");
|
||||
struct st_kdl_value v;
|
||||
struct st_error *err;
|
||||
|
||||
err = st_kdl_value_from_token_annotated(&r, &a128, &v);
|
||||
munit_assert_not_null(err);
|
||||
munit_assert_int(st_error_category_of(err), ==, ST_ERR_KDL_PARSE);
|
||||
munit_assert_true(strstr(st_error_message(err), "unsupported") != NULL);
|
||||
st_error_free(err);
|
||||
|
||||
err = st_kdl_value_from_token_annotated(&r, &u128, &v);
|
||||
munit_assert_not_null(err);
|
||||
munit_assert_true(strstr(st_error_message(err), "unsupported") != NULL);
|
||||
st_error_free(err);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
/* ---- end-to-end annotation integration (through the parser) ------------ */
|
||||
|
||||
static MunitResult
|
||||
test_parser_annotation_arg(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_error *err = NULL;
|
||||
struct st_kdl_document *doc = st_kdl_parse("node (u8)42", "t.kdl", &err);
|
||||
struct st_kdl_node *n;
|
||||
struct st_kdl_value v;
|
||||
|
||||
munit_assert_not_null(doc);
|
||||
munit_assert_null(err);
|
||||
|
||||
n = doc->nodes;
|
||||
munit_assert_not_null(n);
|
||||
munit_assert_not_null(n->args);
|
||||
munit_assert_int(n->args->value.kind, ==, ST_TOK_NUMBER);
|
||||
munit_assert_not_null(n->args->annotation);
|
||||
munit_assert_int(n->args->annotation->kind, ==, ST_TOK_TYPE);
|
||||
munit_assert_memory_equal(2, n->args->annotation->text, "u8");
|
||||
|
||||
err = st_kdl_value_from_token_annotated(&n->args->value,
|
||||
n->args->annotation, &v);
|
||||
munit_assert_null(err);
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_UINT);
|
||||
munit_assert_ullong(v.as.u, ==, 42);
|
||||
munit_assert_string_equal(v.annotation, "u8");
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
st_kdl_document_free(doc);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_parser_annotation_prop(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
struct st_error *err = NULL;
|
||||
struct st_kdl_document *doc = st_kdl_parse("node key=(u8)42", "t.kdl", &err);
|
||||
struct st_kdl_node *n;
|
||||
struct st_kdl_value v;
|
||||
|
||||
munit_assert_not_null(doc);
|
||||
munit_assert_null(err);
|
||||
|
||||
n = doc->nodes;
|
||||
munit_assert_not_null(n);
|
||||
munit_assert_not_null(n->props);
|
||||
munit_assert_int(n->props->value.kind, ==, ST_TOK_NUMBER);
|
||||
munit_assert_not_null(n->props->annotation);
|
||||
munit_assert_int(n->props->annotation->kind, ==, ST_TOK_TYPE);
|
||||
munit_assert_memory_equal(2, n->props->annotation->text, "u8");
|
||||
|
||||
err = st_kdl_value_from_token_annotated(&n->props->value,
|
||||
n->props->annotation, &v);
|
||||
munit_assert_null(err);
|
||||
munit_assert_int(v.kind, ==, ST_KDL_VAL_UINT);
|
||||
munit_assert_ullong(v.as.u, ==, 42);
|
||||
st_kdl_value_free(&v);
|
||||
|
||||
st_kdl_document_free(doc);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_free_null(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
|
||||
st_kdl_value_free(NULL);
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitResult
|
||||
test_kind_name(const MunitParameter params[], void *data)
|
||||
{
|
||||
(void)params;
|
||||
(void)data;
|
||||
|
||||
munit_assert_string_equal(st_kdl_value_kind_name(ST_KDL_VAL_STRING),
|
||||
"string");
|
||||
munit_assert_string_equal(st_kdl_value_kind_name(ST_KDL_VAL_NULL), "null");
|
||||
munit_assert_string_equal(st_kdl_value_kind_name((enum st_kdl_value_kind)99),
|
||||
"?");
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
static MunitTest tests[] = {
|
||||
{ "/value/radix-ints", test_radix_ints, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/decimal-and-sign", test_decimal_and_sign, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/floats", test_floats, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/exponents", test_exponents, NULL, NULL, MUNIT_TEST_OPTION_NONE,
|
||||
NULL },
|
||||
{ "/value/keyword-numbers", test_keyword_numbers, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/bool-null", test_bool_null, NULL, NULL, MUNIT_TEST_OPTION_NONE,
|
||||
NULL },
|
||||
{ "/value/ident-and-quoted", test_ident_and_quoted, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/escapes", test_escapes, NULL, NULL, MUNIT_TEST_OPTION_NONE,
|
||||
NULL },
|
||||
{ "/value/raw-string", test_raw_string, NULL, NULL, MUNIT_TEST_OPTION_NONE,
|
||||
NULL },
|
||||
{ "/value/multiline-dedent", test_multiline_dedent, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/multiline-escaped-newline", test_multiline_escaped_newline, NULL,
|
||||
NULL, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/unknown-escape", test_unknown_escape, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/unterminated-escape", test_unterminated_escape, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/unicode-out-of-range", test_unicode_out_of_range, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/bad-radix", test_bad_radix, NULL, NULL, MUNIT_TEST_OPTION_NONE,
|
||||
NULL },
|
||||
{ "/value/integer-overflow", test_integer_overflow, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/annotation-u8", test_annotation_u8, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/annotation-unsigned-negative", test_annotation_unsigned_rejects_negative,
|
||||
NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/annotation-unsupported-width", test_annotation_unsupported_width,
|
||||
NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/parser-annotation-arg", test_parser_annotation_arg, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/parser-annotation-prop", test_parser_annotation_prop, NULL, NULL,
|
||||
MUNIT_TEST_OPTION_NONE, NULL },
|
||||
{ "/value/free-null", test_free_null, NULL, NULL, MUNIT_TEST_OPTION_NONE,
|
||||
NULL },
|
||||
{ "/value/kind-name", test_kind_name, NULL, NULL, MUNIT_TEST_OPTION_NONE,
|
||||
NULL },
|
||||
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
|
||||
};
|
||||
|
||||
static const MunitSuite suite = {
|
||||
"/value", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE,
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char *argv[MUNIT_ARRAY_PARAM(argc + 1)])
|
||||
{
|
||||
return munit_suite_main(&suite, NULL, argc, argv);
|
||||
}
|
||||
Reference in New Issue
Block a user