From 7beef72dea11cf421f6ab7fce81d8592776cf79f Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Fri, 29 Oct 2021 09:50:16 -0700 Subject: Add test that runs all examples and makes sure they don't crash --- examples/c_files/basic.c | 3 +++ examples/dump_ast.py | 5 ++++- examples/func_defs_add_param.py | 3 +++ examples/rewrite_ast.py | 2 ++ examples/serialize_ast.py | 27 +++++++++++++++------------ tests/test_examples.py | 33 +++++++++++++++++++++++++++++++++ tests/test_util.py | 23 +++++++++++++++++++++++ 7 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 examples/c_files/basic.c create mode 100644 tests/test_examples.py diff --git a/examples/c_files/basic.c b/examples/c_files/basic.c new file mode 100644 index 0000000..4cce7f6 --- /dev/null +++ b/examples/c_files/basic.c @@ -0,0 +1,3 @@ +int main() { + return 0; +} diff --git a/examples/dump_ast.py b/examples/dump_ast.py index b7c3273..e82d038 100644 --- a/examples/dump_ast.py +++ b/examples/dump_ast.py @@ -18,7 +18,10 @@ from pycparser import parse_file if __name__ == "__main__": argparser = argparse.ArgumentParser('Dump AST') - argparser.add_argument('filename', help='name of file to parse') + argparser.add_argument('filename', + default='examples/c_files/basic.c', + nargs='?', + help='name of file to parse') argparser.add_argument('--coord', help='show coordinates in the dump', action='store_true') args = argparser.parse_args() diff --git a/examples/func_defs_add_param.py b/examples/func_defs_add_param.py index 9eb35c9..e9a89d1 100644 --- a/examples/func_defs_add_param.py +++ b/examples/func_defs_add_param.py @@ -9,6 +9,9 @@ #----------------------------------------------------------------- from __future__ import print_function +import sys +sys.path.extend(['.', '..']) + from pycparser import c_parser, c_ast, c_generator text = r""" diff --git a/examples/rewrite_ast.py b/examples/rewrite_ast.py index 164abb5..ea9adb3 100644 --- a/examples/rewrite_ast.py +++ b/examples/rewrite_ast.py @@ -7,7 +7,9 @@ # License: BSD #----------------------------------------------------------------- from __future__ import print_function +import sys +sys.path.extend(['.', '..']) from pycparser import c_parser text = r""" diff --git a/examples/serialize_ast.py b/examples/serialize_ast.py index e0f8aa3..8669a0a 100644 --- a/examples/serialize_ast.py +++ b/examples/serialize_ast.py @@ -9,7 +9,9 @@ #----------------------------------------------------------------- from __future__ import print_function import pickle +import sys +sys.path.extend(['.', '..']) from pycparser import c_parser text = r""" @@ -19,18 +21,19 @@ void func(void) } """ -parser = c_parser.CParser() -ast = parser.parse(text) +if __name__ == '__main__': + parser = c_parser.CParser() + ast = parser.parse(text) -# Since AST nodes use __slots__ for faster attribute access and -# space saving, it needs Pickle's protocol version >= 2. -# The default version is 3 for python 3.x and 1 for python 2.7. -# You can always select the highest available protocol with the -1 argument. + # Since AST nodes use __slots__ for faster attribute access and + # space saving, it needs Pickle's protocol version >= 2. + # The default version is 3 for python 3.x and 1 for python 2.7. + # You can always select the highest available protocol with the -1 argument. -with open('ast', 'wb') as f: - pickle.dump(ast, f, protocol=-1) + with open('ast', 'wb') as f: + pickle.dump(ast, f, protocol=-1) -# Deserialize. -with open('ast', 'rb') as f: - ast = pickle.load(f) - ast.show() + # Deserialize. + with open('ast', 'rb') as f: + ast = pickle.load(f) + ast.show() diff --git a/tests/test_examples.py b/tests/test_examples.py new file mode 100644 index 0000000..24cf16e --- /dev/null +++ b/tests/test_examples.py @@ -0,0 +1,33 @@ +import os +import sys +import time +import unittest + +sys.path.insert(0, '.') +from tests.test_util import run_exe + +EMIT_ELAPSED_TIME = False + +# Runs all pycparser examples with no command-line arguments and makes sure they +# run successfully (return code = 0), without actually verifying their output. +class TestExamplesSucceed(unittest.TestCase): + def test_all_examples(self): + root = './examples' + for filename in os.listdir(root): + if os.path.splitext(filename)[1] == '.py': + # TODO: It would be nice to use subTest here, but that's not + # available in Python 2.7 + # Use it when we finally drop Python 2... + path = os.path.join(root, filename) + t1 = time.time() + rc, stdout = run_exe(path) + elapsed = time.time() - t1 + if EMIT_ELAPSED_TIME: + print('{}... elapsed: {}'.format(filename, elapsed)) + self.assertEqual( + rc, 0, 'example "{}" failed with stdout =\n{}'.format(filename, stdout)) + + +if __name__ == '__main__': + EMIT_ELAPSED_TIME = True + unittest.main() diff --git a/tests/test_util.py b/tests/test_util.py index 3ac3886..435962d 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -7,7 +7,10 @@ # This file contributed by vit9696@users.noreply.github.com # License: BSD #------------------------------------------------------------------------------ +import os import platform +import subprocess +import sys def cpp_supported(): @@ -29,3 +32,23 @@ def cpp_args(args=[]): if platform.system() == 'Darwin': return ['-E'] + args return args + +def _bytes2str(b): + if sys.version_info[0] == 3: + return b.decode('latin-1') + else: + return b + +def run_exe(exe_path, args=[], echo=False): + """ Runs the given executable as a subprocess, given the + list of arguments. Captures its return code (rc) and stdout and + returns a pair: rc, stdout_str + """ + popen_cmd = [exe_path] + args + if os.path.splitext(exe_path)[1] == '.py': + popen_cmd.insert(0, sys.executable) + if echo: + print('[cmd]', ' '.join(popen_cmd)) + proc = subprocess.Popen(popen_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc_stdout = proc.communicate()[0] + return proc.returncode, _bytes2str(proc_stdout) -- cgit v1.2.1