#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "idl/processor.h"
#include "CUnit/Test.h"
static idl_retcode_t parse_string(const char *str, idl_pstate_t **pstatep)
{
idl_retcode_t ret;
idl_pstate_t *pstate = NULL;
if ((ret = idl_create_pstate(0u, NULL, &pstate)))
return ret;
assert(pstate);
ret = idl_parse_string(pstate, str);
if (ret == IDL_RETCODE_OK)
*pstatep = pstate;
else
idl_delete_pstate(pstate);
return ret;
}
static void test_bad_use(const char *str)
{
idl_retcode_t ret;
idl_pstate_t *pstate = NULL;
ret = parse_string(str, &pstate);
CU_ASSERT_EQ (ret, IDL_RETCODE_SEMANTIC_ERROR);
CU_ASSERT_EQ (pstate, NULL);
idl_delete_pstate(pstate);
}
CU_Test(idl_pragma, keylist_bad_use)
{
const char *str[] = {
"#pragma keylist foo bar",
"struct s { char c; };\n"
"#pragma keylist s foo\n",
"struct s { char c; };\n"
"#pragma keylist s c\n"
"#pragma keylist s c\n",
"struct s { char c; };\n"
"#pragma keylist s c c\n",
NULL
};
for (const char **ptr = str; *ptr; ptr++)
test_bad_use(*ptr);
}
static void test_keylist(const char *str, idl_retcode_t exp)
{
idl_retcode_t ret;
idl_pstate_t *pstate = NULL;
ret = parse_string(str, &pstate);
CU_ASSERT_EQ (ret, exp);
if (ret == IDL_RETCODE_OK) {
CU_ASSERT_NEQ_FATAL (pstate, NULL);
CU_ASSERT_NEQ_FATAL (pstate->root, NULL);
const void *node = pstate->root;
const idl_keylist_t *keylist = NULL;
while (idl_is_enum(node))
node = idl_next(node);
CU_ASSERT (idl_is_struct(node));
if (node && idl_is_struct(node))
keylist = ((const idl_struct_t *)node)->keylist;
CU_ASSERT_NEQ (keylist, NULL);
}
idl_delete_pstate(pstate);
}
CU_Test(idl_pragma, keylist)
{
#define TEST(type) "struct s { " type " m %s; };\n" \
"#pragma keylist s m\n"
const char *fmts[] = {
TEST("boolean"),
TEST("char"),
TEST("octet"),
TEST("short"),
TEST("unsigned short"),
TEST("long"),
TEST("unsigned long"),
TEST("long long"),
TEST("unsigned long long"),
"enum abc { A, B };\n" TEST("abc"),
TEST("string")
};
#undef TEST
for (size_t i=0, n=(sizeof(fmts)/sizeof(fmts[0])); i < n; i++) {
char buf[128];
(void)snprintf(buf, sizeof(buf), fmts[i], "");
test_keylist(buf, IDL_RETCODE_OK);
if (i == n - 1)
continue;
(void)snprintf(buf, sizeof(buf), fmts[i], "[2]");
test_keylist(buf, IDL_RETCODE_OK);
}
}
CU_Test(idl_pragma, keylist_nested_key)
{
idl_retcode_t ret;
idl_pstate_t *pstate = NULL;
idl_struct_t *s1;
static const char str[] = "module m1 { struct s2 { char c; }; };\n"
"struct s1 { m1::s2 s; };\n"
"#pragma keylist s1 s.c";
ret = parse_string(str, &pstate);
CU_ASSERT_EQ_FATAL (ret, IDL_RETCODE_OK);
CU_ASSERT_NEQ_FATAL (pstate, NULL);
s1 = idl_next(pstate->root);
CU_ASSERT_FATAL (idl_is_struct(s1));
CU_ASSERT_NEQ ((idl_mask(s1->keylist) & IDL_KEYLIST), 0);
idl_delete_pstate(pstate);
}
CU_Test(idl_pragma, keylist_conflicting)
{
idl_retcode_t ret;
idl_pstate_t *pstate = NULL;
#define NESTED2 "struct i { char i1; char i2; }; struct o { i o1; i o2; }; struct p { i o1; i o2; };\n"
#define NESTED3 "struct i { char i1; char i2; }; struct m { i m1; i m2; }; struct o { m o1; m o2; }; struct p { m p1; m p2; };\n"
static const struct {
const char *idl;
idl_retcode_t ret;
} tests[] = {
{ NESTED2 "#pragma keylist o o1.i1 o2.i2\n", IDL_RETCODE_SEMANTIC_ERROR },
{ NESTED2 "#pragma keylist o o1.i1 o1.i2 o2.i1\n", IDL_RETCODE_SEMANTIC_ERROR },
{ NESTED2 "#pragma keylist o o1.i1 o1.i2\n", IDL_RETCODE_OK },
{ NESTED2 "#pragma keylist o o1.i1 o1.i2 o2.i1 o2.i2\n", IDL_RETCODE_OK },
{ NESTED3 "#pragma keylist o o1.m1.i1 o1.m2.i2\n", IDL_RETCODE_SEMANTIC_ERROR },
{ NESTED3 "#pragma keylist o o1.m1.i1 o2.m1.i2\n", IDL_RETCODE_SEMANTIC_ERROR },
{ NESTED3 "#pragma keylist o o1.m1.i1 o1.m1.i2 o1.m2.i1\n", IDL_RETCODE_SEMANTIC_ERROR },
{ NESTED3 "#pragma keylist o o1.m1.i1 o1.m1.i2 o2.m1.i1\n", IDL_RETCODE_SEMANTIC_ERROR },
{ NESTED3 "#pragma keylist o o1.m1.i1 o1.m1.i2 o2.m1.i1 o2.m1.i2 o1.m2.i1\n", IDL_RETCODE_SEMANTIC_ERROR },
{ NESTED3 "#pragma keylist o o1.m1.i1 o1.m1.i2\n", IDL_RETCODE_OK },
{ NESTED3 "#pragma keylist o o1.m1.i1 o1.m1.i2 o1.m2.i1 o1.m2.i2\n", IDL_RETCODE_OK },
{ NESTED2 "#pragma keylist o o1.i1\n#pragma keylist p o1.i1 o1.i2\n", IDL_RETCODE_SEMANTIC_ERROR },
{ NESTED3 "#pragma keylist o o1.m1.i1\n#pragma keylist p p1.m2.i1\n", IDL_RETCODE_SEMANTIC_ERROR },
{ NESTED3 "#pragma keylist o o1.m1.i1\n#pragma keylist p p1.m1.i2\n", IDL_RETCODE_SEMANTIC_ERROR },
{ "struct i { char i1; char i2; }; struct m { i m1; }; struct o { m o1; i o2; };\n"
"#pragma keylist o o1.m1.i1 o1.m1.i2 o2.i1\n", IDL_RETCODE_SEMANTIC_ERROR },
{ "struct i { char i1; char i2; }; struct m { i m1; }; struct o { m o1; i o2; };\n"
"#pragma keylist o o1.m1.i1 o2.i1\n", IDL_RETCODE_OK },
{ "struct i { char i1; char i2; }; struct j { char j1; char j2; }; struct o { i o1; j o2; j o3; };\n"
"#pragma keylist o o1.i1 o1.i2 o2.j1 o2.j2 o3.j1\n", IDL_RETCODE_SEMANTIC_ERROR },
{ "struct i { char i1; char i2; }; struct j { char j1; char j2; }; struct o { i o1; j o2; j o3; };\n"
"#pragma keylist o o1.i1 o1.i2 o2.j1 o2.j2\n", IDL_RETCODE_OK }
};
for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++) {
printf("Test idl: %s\n", tests[i].idl);
ret = parse_string(tests[i].idl, &pstate);
CU_ASSERT_EQ_FATAL (ret, tests[i].ret);
if (ret != tests[i].ret)
printf("retcode: %d\n%s\n", ret, tests[i].idl);
idl_delete_pstate(pstate);
pstate = NULL;
}
}
CU_Test(idl_pragma, keylist_scoped_name)
{
idl_retcode_t ret;
idl_pstate_t *pstate = NULL;
idl_module_t *m1;
idl_struct_t *s1;
static const char str[] = "module m1 { struct s1 { char c; }; };\n"
"#pragma keylist m1::s1 c";
ret = parse_string(str, &pstate);
CU_ASSERT_EQ_FATAL (ret, IDL_RETCODE_OK);
CU_ASSERT_NEQ_FATAL (pstate, NULL);
m1 = (idl_module_t *)pstate->root;
CU_ASSERT_FATAL (idl_is_module(m1));
s1 = (idl_struct_t *)m1->definitions;
CU_ASSERT_FATAL (idl_is_struct(s1));
CU_ASSERT_NEQ ((idl_mask(s1->keylist) & IDL_KEYLIST), 0);
idl_delete_pstate(pstate);
}
CU_Test(idl_pragma, keylist_outer_scope)
{
idl_retcode_t ret;
idl_pstate_t *pstate = NULL;
idl_struct_t *s1;
static const char str[] = "struct s1 { char c; };\n"
"module m1 {\n"
" struct s2 { char c; };\n"
" #pragma keylist s1 c\n"
"};\n";
ret = parse_string(str, &pstate);
CU_ASSERT_EQ_FATAL (ret, IDL_RETCODE_OK);
CU_ASSERT_NEQ_FATAL (pstate, NULL);
s1 = (idl_struct_t *)pstate->root;
CU_ASSERT_FATAL (idl_is_struct(s1));
CU_ASSERT_NEQ ((idl_mask(s1->keylist) & IDL_KEYLIST), 0);
idl_delete_pstate(pstate);
}
CU_Test(idl_pragma, unknown)
{
idl_retcode_t ret;
idl_pstate_t *pstate = NULL;
idl_struct_t *s1;
static const char str[] = "struct s1 { char c; };\n"
"#pragma foo \"bar::baz\"";
ret = parse_string(str, &pstate);
CU_ASSERT_EQ_FATAL (ret, IDL_RETCODE_OK);
CU_ASSERT_NEQ_FATAL (pstate, NULL);
s1 = (idl_struct_t *)pstate->root;
CU_ASSERT_FATAL (idl_is_struct(s1));
idl_delete_pstate(pstate);
}