aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_c_generator.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_c_generator.py')
-rw-r--r--tests/test_c_generator.py337
1 files changed, 337 insertions, 0 deletions
diff --git a/tests/test_c_generator.py b/tests/test_c_generator.py
new file mode 100644
index 0000000..3727f91
--- /dev/null
+++ b/tests/test_c_generator.py
@@ -0,0 +1,337 @@
+import sys
+import textwrap
+import unittest
+
+# Run from the root dir
+sys.path.insert(0, '.')
+
+from pycparser import c_parser, c_generator, c_ast
+
+_c_parser = c_parser.CParser(
+ lex_optimize=False,
+ yacc_debug=True,
+ yacc_optimize=False,
+ yacctab='yacctab')
+
+
+def compare_asts(ast1, ast2):
+ if type(ast1) != type(ast2):
+ return False
+ if isinstance(ast1, tuple) and isinstance(ast2, tuple):
+ if ast1[0] != ast2[0]:
+ return False
+ ast1 = ast1[1]
+ ast2 = ast2[1]
+ return compare_asts(ast1, ast2)
+ for attr in ast1.attr_names:
+ if getattr(ast1, attr) != getattr(ast2, attr):
+ return False
+ for i, c1 in enumerate(ast1.children()):
+ if compare_asts(c1, ast2.children()[i]) == False:
+ return False
+ return True
+
+
+def parse_to_ast(src):
+ return _c_parser.parse(src)
+
+
+class TestFunctionDeclGeneration(unittest.TestCase):
+ class _FuncDeclVisitor(c_ast.NodeVisitor):
+ def __init__(self):
+ self.stubs = []
+
+ def visit_FuncDecl(self, node):
+ gen = c_generator.CGenerator()
+ self.stubs.append(gen.visit(node))
+
+ def test_partial_funcdecl_generation(self):
+ src = r'''
+ void noop(void);
+ void *something(void *thing);
+ int add(int x, int y);'''
+ ast = parse_to_ast(src)
+ v = TestFunctionDeclGeneration._FuncDeclVisitor()
+ v.visit(ast)
+ self.assertEqual(len(v.stubs), 3)
+ self.assertTrue(r'void noop(void)' in v.stubs)
+ self.assertTrue(r'void *something(void *thing)' in v.stubs)
+ self.assertTrue(r'int add(int x, int y)' in v.stubs)
+
+
+class TestCtoC(unittest.TestCase):
+ def _run_c_to_c(self, src):
+ ast = parse_to_ast(src)
+ generator = c_generator.CGenerator()
+ return generator.visit(ast)
+
+ def _assert_ctoc_correct(self, src):
+ """ Checks that the c2c translation was correct by parsing the code
+ generated by c2c for src and comparing the AST with the original
+ AST.
+ """
+ src2 = self._run_c_to_c(src)
+ self.assertTrue(compare_asts(parse_to_ast(src), parse_to_ast(src2)),
+ src2)
+
+ def test_trivial_decls(self):
+ self._assert_ctoc_correct('int a;')
+ self._assert_ctoc_correct('int b, a;')
+ self._assert_ctoc_correct('int c, b, a;')
+
+ def test_complex_decls(self):
+ self._assert_ctoc_correct('int** (*a)(void);')
+ self._assert_ctoc_correct('int** (*a)(void*, int);')
+ self._assert_ctoc_correct('int (*b)(char * restrict k, float);')
+ self._assert_ctoc_correct('int test(const char* const* arg);')
+ self._assert_ctoc_correct('int test(const char** const arg);')
+
+ #s = 'int test(const char* const* arg);'
+ #parse_to_ast(s).show()
+
+ def test_ternary(self):
+ self._assert_ctoc_correct('''
+ int main(void)
+ {
+ int a, b;
+ (a == 0) ? (b = 1) : (b = 2);
+ }''')
+
+ def test_casts(self):
+ self._assert_ctoc_correct(r'''
+ int main() {
+ int b = (int) f;
+ int c = (int*) f;
+ }''')
+ self._assert_ctoc_correct(r'''
+ int main() {
+ int a = (int) b + 8;
+ int t = (int) c;
+ }
+ ''')
+
+ def test_initlist(self):
+ self._assert_ctoc_correct('int arr[] = {1, 2, 3};')
+
+ def test_exprs(self):
+ self._assert_ctoc_correct('''
+ int main(void)
+ {
+ int a;
+ int b = a++;
+ int c = ++a;
+ int d = a--;
+ int e = --a;
+ }''')
+
+ def test_statements(self):
+ # note two minuses here
+ self._assert_ctoc_correct(r'''
+ int main() {
+ int a;
+ a = 5;
+ ;
+ b = - - a;
+ return a;
+ }''')
+
+ def test_struct_decl(self):
+ self._assert_ctoc_correct(r'''
+ typedef struct node_t {
+ struct node_t* next;
+ int data;
+ } node;
+ ''')
+
+ def test_krstyle(self):
+ self._assert_ctoc_correct(r'''
+ int main(argc, argv)
+ int argc;
+ char** argv;
+ {
+ return 0;
+ }
+ ''')
+
+ def test_switchcase(self):
+ self._assert_ctoc_correct(r'''
+ int main() {
+ switch (myvar) {
+ case 10:
+ {
+ k = 10;
+ p = k + 1;
+ break;
+ }
+ case 20:
+ case 30:
+ return 20;
+ default:
+ break;
+ }
+ }
+ ''')
+
+ def test_nest_initializer_list(self):
+ self._assert_ctoc_correct(r'''
+ int main()
+ {
+ int i[1][1] = { { 1 } };
+ }''')
+
+ def test_nest_named_initializer(self):
+ self._assert_ctoc_correct(r'''struct test
+ {
+ int i;
+ struct test_i_t
+ {
+ int k;
+ } test_i;
+ int j;
+ };
+ struct test test_var = {.i = 0, .test_i = {.k = 1}, .j = 2};
+ ''')
+
+ def test_expr_list_in_initializer_list(self):
+ self._assert_ctoc_correct(r'''
+ int main()
+ {
+ int i[1] = { (1, 2) };
+ }''')
+
+ def test_issue36(self):
+ self._assert_ctoc_correct(r'''
+ int main() {
+ }''')
+
+ def test_issue37(self):
+ self._assert_ctoc_correct(r'''
+ int main(void)
+ {
+ unsigned size;
+ size = sizeof(size);
+ return 0;
+ }''')
+
+ def test_issue66(self):
+ # A non-existing body must not be generated
+ # (previous valid behavior, still working)
+ self._assert_ctoc_correct(r'''
+ struct foo;
+ ''')
+ # An empty body must be generated
+ # (added behavior)
+ self._assert_ctoc_correct(r'''
+ struct foo {};
+ ''')
+
+ def test_issue83(self):
+ self._assert_ctoc_correct(r'''
+ void x(void) {
+ int i = (9, k);
+ }
+ ''')
+
+ def test_issue84(self):
+ self._assert_ctoc_correct(r'''
+ void x(void) {
+ for (int i = 0;;)
+ i;
+ }
+ ''')
+
+ def test_issue246(self):
+ self._assert_ctoc_correct(r'''
+ int array[3] = {[0] = 0, [1] = 1, [1+1] = 2};
+ ''')
+
+ def test_exprlist_with_semi(self):
+ self._assert_ctoc_correct(r'''
+ void x() {
+ if (i < j)
+ tmp = C[i], C[i] = C[j], C[j] = tmp;
+ if (i <= j)
+ i++, j--;
+ }
+ ''')
+
+ def test_exprlist_with_subexprlist(self):
+ self._assert_ctoc_correct(r'''
+ void x() {
+ (a = b, (b = c, c = a));
+ }
+ ''')
+
+ def test_comma_operator_funcarg(self):
+ self._assert_ctoc_correct(r'''
+ void f(int x) { return x; }
+ int main(void) { f((1, 2)); return 0; }
+ ''')
+
+ def test_comma_op_in_ternary(self):
+ self._assert_ctoc_correct(r'''
+ void f() {
+ (0, 0) ? (0, 0) : (0, 0);
+ }
+ ''')
+
+ def test_comma_op_assignment(self):
+ self._assert_ctoc_correct(r'''
+ void f() {
+ i = (a, b, c);
+ }
+ ''')
+
+ def test_pragma(self):
+ self._assert_ctoc_correct(r'''
+ #pragma foo
+ void f() {
+ #pragma bar
+ i = (a, b, c);
+ }
+ typedef struct s {
+ #pragma baz
+ } s;
+ ''')
+
+ def test_compound_literal(self):
+ self._assert_ctoc_correct('char **foo = (char *[]){ "x", "y", "z" };')
+ self._assert_ctoc_correct('int i = ++(int){ 1 };')
+ self._assert_ctoc_correct('struct foo_s foo = (struct foo_s){ 1, 2 };')
+
+ def test_enum(self):
+ self._assert_ctoc_correct(r'''
+ enum e
+ {
+ a,
+ b = 2,
+ c = 3
+ };
+ ''')
+ self._assert_ctoc_correct(r'''
+ enum f
+ {
+ g = 4,
+ h,
+ i
+ };
+ ''')
+
+ def test_enum_typedef(self):
+ self._assert_ctoc_correct('typedef enum EnumName EnumTypedefName;')
+
+ def test_generate_struct_union_enum_exception(self):
+ generator = c_generator.CGenerator()
+ self.assertRaises(
+ AssertionError,
+ generator._generate_struct_union_enum,
+ n=c_ast.Struct(
+ name='TestStruct',
+ decls=[],
+ ),
+ name='',
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()