From 6317b8938f85acc148c6ee40fa7197c6f645ed08 Mon Sep 17 00:00:00 2001 From: Zhuanhao Wu Date: Mon, 13 Jan 2020 13:04:05 -0500 Subject: [PATCH] A new test that breaks current conversion --- tests/verilog-conversion/conftest.py | 27 +++++++++ tests/verilog-conversion/driver.py | 12 +++- tests/verilog-conversion/run.py | 39 +----------- tests/verilog-conversion/test_sreg.py | 73 +++++++++++++++++++---- tests/verilog-conversion/util/__init__.py | 0 tests/verilog-conversion/util/conf.py | 64 ++++++++++++++++++++ tests/verilog-conversion/util/sexpdiff.py | 17 ++++++ tests/verilog-conversion/util/vdiff.py | 3 +- tests/verilog-conversion/util/vparser.py | 4 +- 9 files changed, 184 insertions(+), 55 deletions(-) create mode 100644 tests/verilog-conversion/conftest.py create mode 100644 tests/verilog-conversion/util/__init__.py create mode 100644 tests/verilog-conversion/util/conf.py create mode 100644 tests/verilog-conversion/util/sexpdiff.py diff --git a/tests/verilog-conversion/conftest.py b/tests/verilog-conversion/conftest.py new file mode 100644 index 000000000..c34502b7f --- /dev/null +++ b/tests/verilog-conversion/conftest.py @@ -0,0 +1,27 @@ +"""Fixtures for testing""" +import pytest +from util.conf import LLNLExampleTestingConfigurations +import driver as drv + + +@pytest.fixture +def llnldriver(): + """fixture for llnl example driver""" + conf = LLNLExampleTestingConfigurations() + llnl_driver = drv.SystemCClangDriver(conf) + return llnl_driver + + +def pytest_addoption(parser): + parser.addoption("--tool-output", action="store_true") + + +def pytest_generate_tests(metafunc): + # This is called for every test. Only get/set command line arguments + # if the argument is specified in the list of test "fixturenames". + if 'tool_output' in metafunc.fixturenames: + if metafunc.config.getoption("tool_output"): + verbose = True + else: + verbose = False + metafunc.parametrize("tool_output", [verbose]) diff --git a/tests/verilog-conversion/driver.py b/tests/verilog-conversion/driver.py index e7bae82c7..6abecae97 100644 --- a/tests/verilog-conversion/driver.py +++ b/tests/verilog-conversion/driver.py @@ -69,6 +69,8 @@ def generate_verilog_from_sexp(self, path, output_folder, keep_v=False, verbose= SystemCClangDriver.PYTHON_CONVERT_TEMPLATE, path ]) + if verbose: + print('cmdline', cmdline) try: if verbose: subprocess.run(cmdline, shell=True) @@ -112,6 +114,7 @@ def generate_sexp(self, path, output_folder, keep_sexp=False, verbose=False): ok = True try: if verbose: + print('cmd: ', ' '.join(cmdline)) subprocess.run(' '.join(cmdline), shell=True) else: with open(os.devnull, 'wb') as null: @@ -137,6 +140,11 @@ def generate_sexp(self, path, output_folder, keep_sexp=False, verbose=False): If any step fails, an exeption will be thrown """ def generate_verilog(self, path, output_folder, verbose): - succ_sexp, sexp_filename = generate_sexp(path, output_folder, keep_sexp=True, verbose=verbose) - succ_v, v_filename = generate_verilog(sexp_filename, output_folder, keep_v=True, verbose=verbose) + succ_sexp, sexp_filename = self.generate_sexp(path, output_folder, keep_sexp=True, verbose=verbose) + if succ_sexp: + assert os.path.isfile(sexp_filename), 'Cannot find generated sexp_filename: {}'.format(sexp_filename) + succ_v, v_filename = self.generate_verilog_from_sexp(sexp_filename, output_folder, keep_v=True, verbose=verbose) + return succ_v, v_filename + else: + return False, None diff --git a/tests/verilog-conversion/run.py b/tests/verilog-conversion/run.py index fc0585826..e90f36234 100644 --- a/tests/verilog-conversion/run.py +++ b/tests/verilog-conversion/run.py @@ -1,44 +1,7 @@ from driver import * from util.vparser import VerilogParser +from util.conf import LLNLExampleTestingConfigurations import tempfile -import contextlib - -class TestingConfigurations(object): - """parameters in this configuration might change""" - - @property - def extra_header_folders(self): - # SystemC Clang build llnl-examples - return self.header_folders - - @property - def positional_arguments(self): - headers = [] - extra_header_folders = self.extra_header_folders - for h in extra_header_folders: - headers.extend(["-I", h]) - return headers - - def __init__(self, header_folders): - self.header_folders = header_folders - -class LLNLExampleTestingConfigurations(TestingConfigurations): - - def __init__(self, header_folders=None): - if header_folders is None: - header_folders = [] - this_folders = header_folders + [ - '/home/allen/working/systemc-clang/examples/llnl-examples/' - ] - super(LLNLExampleTestingConfigurations, self).__init__(this_folders) - -@contextlib.contextmanager -def make_temp_directory(): - temp_dir = tempfile.mkdtemp() - try: - yield temp_dir - finally: - shutil.rmtree(temp_dir) def main(): conf = LLNLExampleTestingConfigurations() diff --git a/tests/verilog-conversion/test_sreg.py b/tests/verilog-conversion/test_sreg.py index 147c0430e..c3895e7f4 100644 --- a/tests/verilog-conversion/test_sreg.py +++ b/tests/verilog-conversion/test_sreg.py @@ -1,16 +1,67 @@ -import os -import sys import pytest -from llnl import run_verilog_matched_test, run_sexp_matched_test +from util.sexpdiff import sexpdiff +from util.vparser import VerilogParser +from shutil import copy -@pytest.mark.xfail(reason="the golden standard now is incorrect") -def test_sreg_sexp(args=None): - assert run_sexp_matched_test('sreg', args), "sreg sexp should match golden standard" -@pytest.mark.skip(reason="no golden standard available for now") -def test_sreg_verilog(args=None): - assert run_verilog_matched_test('sreg', args), "sreg verilog should match golden standard" +def test_sreg_sexp(tmpdir, llnldriver, tool_output): + conf = llnldriver.conf + filename = conf.get_module_name('sreg.cpp') + output_folder = tmpdir + res, filename = llnldriver.generate_sexp( + path=filename, + output_folder=output_folder, + verbose=tool_output, + keep_sexp=True + ) + assert res, "should convert to sexpression" + diff_res, diff_str = sexpdiff( + filename, + conf.get_golden_sexp_name('sreg_hdl.txt') + ) + if diff_res: + print(diff_str) + assert not diff_res, 'should match golden standard' + + +def test_sreg_verilog(tmpdir, llnldriver, tool_output): + conf = llnldriver.conf + filename = conf.get_module_name('sreg.cpp') + output_folder = tmpdir + res, filename = llnldriver.generate_verilog( + path=filename, + output_folder=output_folder, + verbose=tool_output + ) + assert res, "should convert to Verilog from cpp" + diff_info = VerilogParser.diff( + filename, + conf.get_golden_verilog_name('sreg_hdl.txt.v') + ) + print(str(diff_info)) + assert diff_info is None, 'should be no diff in Verilog' + +def test_sreg_sexp_to_verilog(tmpdir, llnldriver, tool_output): + conf = llnldriver.conf + filename = conf.get_golden_sexp_name('sreg_hdl.txt') + output_folder = tmpdir + copy(filename, str(output_folder) + '/') + res, filename = llnldriver.generate_verilog_from_sexp( + path=str(output_folder) + '/sreg_hdl.txt', + output_folder=output_folder, + keep_v=True, + verbose=tool_output + ) + assert res, "should convert to Verilog from sexp" + print('filename: ', filename) + print('golden: ', conf.get_golden_verilog_name('sreg_hdl.txt.v')) + diff_info = VerilogParser.diff( + filename, + conf.get_golden_verilog_name('sreg_hdl.txt.v') + ) + print(str(diff_info)) + assert diff_info is None, 'should be no diff in Verilog' if __name__ == '__main__': - test_sreg_verilog(args) - test_sreg_sexp(args) + test_sreg_verilog() + test_sreg_sexp() diff --git a/tests/verilog-conversion/util/__init__.py b/tests/verilog-conversion/util/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/verilog-conversion/util/conf.py b/tests/verilog-conversion/util/conf.py new file mode 100644 index 000000000..fab61e85c --- /dev/null +++ b/tests/verilog-conversion/util/conf.py @@ -0,0 +1,64 @@ +"""Configuration classes for handling directories etc""" +import os + + +class TestingConfigurations(object): + """parameters in this configuration might change""" + TEST_DATA_ROOT = os.environ['SYSTEMC_CLANG_BUILD_DIR'] + "../systemc-clang/examples/" + + @property + def extra_header_folders(self): + """acessor for header folders""" + # SystemC Clang build llnl-examples + return self.header_folders + + @property + def positional_arguments(self): + """positional arguments for the systemc-clang command""" + headers = [] + extra_header_folders = self.extra_header_folders + for header in extra_header_folders: + headers.extend(["-I", header]) + return headers + + def get_module_name(self, basename): + return self.root_folder + '/' + basename + + def get_golden_sexp_name(self, basename): + return self.golden_folder + '/' + basename + + def get_golden_verilog_name(self, basename): + return self.golden_folder + '/' + basename + + def __init__(self, root_folder, golden_folder, header_folders): + self.header_folders = header_folders + self.root_folder = root_folder + self.golden_folder = golden_folder + + +class LLNLExampleTestingConfigurations(TestingConfigurations): + """parameters for LLNL examples""" + + def __init__(self, header_folders=None): + if header_folders is None: + header_folders = [] + this_folders = header_folders + [ + '{}/llnl-examples/'.format(TestingConfigurations.TEST_DATA_ROOT) + ] + root_folder = os.environ['SYSTEMC_CLANG_BUILD_DIR'] + '/' + 'tests/data/verilog-conversion/llnl-examples/' + golden_folder = root_folder + 'handcrafted/' + super(LLNLExampleTestingConfigurations, self).__init__(root_folder, golden_folder, this_folders) + + +class ExampleTestingConfigurations(TestingConfigurations): + """parameters for ex_* examples""" + + def __init__(self, root_folder, ex_id, header_folders=None): + if header_folders is None: + header_folders = [] + this_folders = header_folders + [ + '{}/ex_{}/'.format(TestingConfigurations.TEST_DATA_ROOT, ex_id) + ] + root_folder = '{}/ex_{}/'.format(TestingConfigurations.TEST_DATA_ROOT, ex_id) + golden_folder = root_folder + 'handcrafted/' + super(ExampleTestingConfigurations, self).__init__(root_folder, golden_folder, this_folders) diff --git a/tests/verilog-conversion/util/sexpdiff.py b/tests/verilog-conversion/util/sexpdiff.py new file mode 100644 index 000000000..cdfddfb79 --- /dev/null +++ b/tests/verilog-conversion/util/sexpdiff.py @@ -0,0 +1,17 @@ +import difflib + +def sexpdiff(this_filename, that_filename): + # Test the equality of golden versus the generated + with open(this_filename, 'r') as f: + sexp_lines = f.readlines() + with open(that_filename, 'r') as f: + golden_lines = f.readlines() + + diff_res = difflib.ndiff(golden_lines, sexp_lines) + diff_only = list(filter(lambda x: x[0] != ' ', diff_res)) + if diff_only: + diff_str = ''.join(diff_res) + else: + diff_str = None + return len(diff_only) != 0, diff_str + diff --git a/tests/verilog-conversion/util/vdiff.py b/tests/verilog-conversion/util/vdiff.py index 377e867c9..7d882f282 100644 --- a/tests/verilog-conversion/util/vdiff.py +++ b/tests/verilog-conversion/util/vdiff.py @@ -35,7 +35,6 @@ class VerilogASTDiff(object): @staticmethod def _diff_traverse(this_node, that_node): """traverses two asts using dfs, stops when different node encountered""" - print("at: {}".format(this_node)) if type(this_node) != type(that_node): return False @@ -48,7 +47,6 @@ def _diff_traverse(this_node, that_node): if a in that_names: that_attr = getattr(that_node, a) if this_attr != that_attr: - print(this_attr, that_attr) diff.append((a, this_attr, a, that_attr)) else: diff.append((a, this_attr, '', '')) @@ -79,3 +77,4 @@ def _diff_traverse(this_node, that_node): def diff_info(this_verilog_ast, that_verilog_ast): """shows the diff information of two ast, including line number and node name""" return VerilogASTDiff._diff_traverse(this_verilog_ast, that_verilog_ast) + diff --git a/tests/verilog-conversion/util/vparser.py b/tests/verilog-conversion/util/vparser.py index 159abf6b3..89972df56 100644 --- a/tests/verilog-conversion/util/vparser.py +++ b/tests/verilog-conversion/util/vparser.py @@ -29,8 +29,8 @@ def diff(this_verilog_filename, that_verilog_filename, this_ast = VerilogParser.parse(this_verilog_filename, include_list, define_list) that_ast = VerilogParser.parse(that_verilog_filename, include_list, define_list) - this_ast.show() - that_ast.show() + # this_ast.show() + # that_ast.show() # show the diff diff_info = VerilogASTDiff.diff_info(this_ast, that_ast)