def setUp(self):
        self.cfg = TestConfiguration()

        self.output_path = out()
        if exists(self.output_path):
            rmtree(self.output_path)
        makedirs(self.output_path)
示例#2
0
    def __init__(self,  # pylint: disable=too-many-locals, too-many-arguments
                 output_path,
                 simulator_factory,
                 clean=False,
                 use_debug_codecs=False,
                 no_color=False,
                 verbose=False,
                 xunit_xml=None,
                 log_level="warning",
                 test_filter=None,
                 list_only=False,
                 list_files_only=False,
                 compile_only=False,
                 keep_compiling=False,
                 elaborate_only=False,
                 vhdl_standard='2008',
                 compile_builtins=True,
                 num_threads=1,
                 exit_0=False):

        self._configure_logging(log_level)
        self._elaborate_only = elaborate_only
        self._output_path = abspath(output_path)

        if no_color:
            self._printer = NO_COLOR_PRINTER
        else:
            self._printer = COLOR_PRINTER

        self._verbose = verbose
        self._xunit_xml = xunit_xml

        self._test_filter = test_filter if test_filter is not None else lambda name: True
        self._list_only = list_only
        self._list_files_only = list_files_only
        self._compile_only = compile_only
        self._keep_compiling = keep_compiling
        self._vhdl_standard = vhdl_standard

        self._tb_filter = tb_filter
        self._configuration = TestConfiguration()
        self._external_preprocessors = []
        self._location_preprocessor = None
        self._check_preprocessor = None
        self._use_debug_codecs = use_debug_codecs

        self._simulator_factory = simulator_factory
        self._create_output_path(clean)

        self._project = None
        self._create_project()
        self._num_threads = num_threads
        self._exit_0 = exit_0

        if compile_builtins:
            self.add_builtins(library_name="vunit_lib")
示例#3
0
    def __init__(self,
                 output_path,
                 clean=False,
                 no_color=False,
                 verbose=False,
                 xunit_xml=None,
                 log_level="warning",
                 test_filter=None,
                 list_only=False,
                 compile_only=False,
                 elaborate_only=False,
                 vhdl_standard='2008',
                 compile_builtins=True,
                 persistent_sim=True,
                 gui=False):

        self._project = Project()

        self._output_path = output_path
        self._clean = clean

        if no_color:
            self._printer = NoColorPrinter
        else:
            self._printer = ColorPrinter

        self._verbose = verbose
        self._xunit_xml = xunit_xml

        level = getattr(logging, log_level.upper())
        logging.basicConfig(filename=None,
                            format='%(levelname)7s - %(message)s',
                            level=level)

        self._test_filter = test_filter if test_filter is not None else lambda name: True
        self._list_only = list_only
        self._compile_only = compile_only
        self._elaborate_only = elaborate_only
        self._vhdl_standard = vhdl_standard

        self._tb_filter = tb_filter
        self._persistent_sim = persistent_sim
        self._gui = gui
        self._configuration = TestConfiguration()
        self._external_preprocessors = []
        self._location_preprocessor = None
        self._check_preprocessor = None

        self._create_output_path()

        if compile_builtins:
            self.add_builtins(library_name="vunit_lib")
示例#4
0
 def helper(config_name, suffix):
     """
     Add config with name and check that the test has the given suffix
     """
     project = ProjectStub()
     lib = project.add_library("lib")
     lib.add_entity("tb_entity",
                    generic_names=["runner_cfg"])
     self.configuration = TestConfiguration()
     self.test_scanner = TestScanner(self.simulator_if, self.configuration)
     self.configuration.add_config(scope=create_scope("lib", "tb_entity"),
                                   name=config_name,
                                   generics=dict())
     tests = self.test_scanner.from_project(project)
     self.assert_has_tests(tests,
                           ["lib.tb_entity" + suffix])
示例#5
0
    def setUp(self):
        self.simulator_if = 'simulator_if'
        self.test_scanner = TestScanner(self.simulator_if, TestConfiguration())

        self.output_path = join(dirname(__file__), "test_scanner_out")

        if exists(self.output_path):
            rmtree(self.output_path)
        makedirs(self.output_path)
示例#6
0
文件: ui.py 项目: darwinbeing/vunit
    def __init__(self,  # pylint: disable=too-many-locals, too-many-arguments
                 output_path,
                 simulator_factory,
                 clean=False,
                 use_debug_codecs=False,
                 no_color=False,
                 verbose=False,
                 xunit_xml=None,
                 log_level="warning",
                 test_filter=None,
                 list_only=False,
                 list_files_only=False,
                 compile_only=False,
                 keep_compiling=False,
                 elaborate_only=False,
                 vhdl_standard='2008',
                 compile_builtins=True,
                 num_threads=1,
                 exit_0=False):

        self._configure_logging(log_level)
        self._elaborate_only = elaborate_only
        self._output_path = abspath(output_path)

        if no_color:
            self._printer = NO_COLOR_PRINTER
        else:
            self._printer = COLOR_PRINTER

        self._verbose = verbose
        self._xunit_xml = xunit_xml

        self._test_filter = test_filter if test_filter is not None else lambda name: True
        self._list_only = list_only
        self._list_files_only = list_files_only
        self._compile_only = compile_only
        self._keep_compiling = keep_compiling
        self._vhdl_standard = vhdl_standard

        self._tb_filter = tb_filter
        self._configuration = TestConfiguration()
        self._external_preprocessors = []
        self._location_preprocessor = None
        self._check_preprocessor = None
        self._use_debug_codecs = use_debug_codecs

        self._simulator_factory = simulator_factory
        self._create_output_path(clean)

        self._project = None
        self._create_project()
        self._num_threads = num_threads
        self._exit_0 = exit_0

        if compile_builtins:
            self.add_builtins(library_name="vunit_lib")
示例#7
0
    def __init__(self,
                 output_path,
                 clean=False,
                 no_color=False,
                 verbose=False,
                 xunit_xml=None,
                 log_level="warning",
                 test_filter=None,
                 list_only=False,
                 compile_only=False,
                 elaborate_only=False,
                 vhdl_standard='2008',
                 compile_builtins=True,
                 persistent_sim=True,
                 gui=False):

        self._project = Project()

        self._output_path = output_path
        self._clean = clean

        if no_color:
            self._printer = NoColorPrinter
        else:
            self._printer = ColorPrinter

        self._verbose = verbose
        self._xunit_xml = xunit_xml

        level = getattr(logging, log_level.upper())
        logging.basicConfig(filename=None, format='%(levelname)7s - %(message)s', level=level)

        self._test_filter = test_filter if test_filter is not None else lambda name : True
        self._list_only = list_only
        self._compile_only = compile_only
        self._elaborate_only = elaborate_only
        self._vhdl_standard = vhdl_standard

        self._tb_filter = tb_filter
        self._persistent_sim = persistent_sim
        self._gui = gui
        self._configuration = TestConfiguration()
        self._external_preprocessors = []
        self._location_preprocessor = None
        self._check_preprocessor = None

        self._create_output_path()

        if compile_builtins:
            self.add_builtins(library_name="vunit_lib")
    def test_no_post_check_when_elaborate_only(self):
        self.cfg = TestConfiguration(elaborate_only=True)
        scope = create_scope("lib", "entity")

        def pre_config():
            return True

        def post_check():
            return True

        self.cfg.add_config(name="name",
                            generics=dict(),
                            pre_config=pre_config,
                            post_check=post_check,
                            scope=scope)

        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg("name", pre_config=pre_config, elaborate_only=True)])
class TestTestConfiguration(unittest.TestCase):
    """
    Test the global test bench configuration
    """
    def setUp(self):
        self.cfg = TestConfiguration()

        self.output_path = out()
        renew_path(self.output_path)

    def test_has_default_configuration(self):
        scope = create_scope("lib", "tb_entity")
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg()])

    def test_set_generic(self):
        scope = create_scope("lib", "tb_entity")
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg()])

        self.cfg.set_generic("global_generic", "global", scope=create_scope())
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(generics={"global_generic": "global"})])

        self.cfg.set_generic("global_generic", "library", scope=create_scope("lib"))
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(generics={"global_generic": "library"})])

        self.cfg.set_generic("global_generic", "entity", scope=create_scope("lib", "tb_entity"))
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(generics={"global_generic": "entity"})])

    def test_set_pli(self):
        scope = create_scope("lib", "tb_entity")
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg("")])

        self.cfg.set_pli(["libglobal.so"], scope=create_scope())
        self.cfg.set_pli(["libfoo.so"], scope=create_scope("lib2"))
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(pli=["libglobal.so"])])

        self.cfg.set_pli(["libfoo.so"], scope=create_scope("lib"))
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(pli=["libfoo.so"])])

        self.cfg.set_pli(["libfoo2.so"], scope=create_scope("lib", "tb_entity"))
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(pli=["libfoo2.so"])])

    def test_add_config(self):
        for value in range(1, 3):
            self.cfg.add_config(scope=create_scope("lib", "tb_entity"),
                                name="value=%i" % value,
                                generics=dict(value=value,
                                              global_value="local value"))

        self.cfg.add_config(scope=create_scope("lib", "tb_entity", "configured test"),
                            name="specific_test_config",
                            generics=dict())

        # Local value should take precedence
        self.cfg.set_generic("global_value", "global value")

        self.assertEqual(self.cfg.get_configurations(create_scope("lib", "tb_entity")),
                         [cfg("value=1",
                              generics={"value": 1, "global_value": "local value"}),
                          cfg("value=2",
                              generics={"value": 2, "global_value": "local value"})])

        self.assertEqual(self.cfg.get_configurations(create_scope("lib", "tb_entity", "test")),
                         [cfg("value=1",
                              generics={"value": 1, "global_value": "local value"}),
                          cfg("value=2",
                              generics={"value": 2, "global_value": "local value"})])

        self.assertEqual(self.cfg.get_configurations(create_scope("lib", "tb_entity", "configured test")),
                         [cfg("specific_test_config", dict(global_value="global value"))])

    def test_disable_ieee_warnings(self):
        lib_scope = create_scope("lib")
        ent_scope = create_scope("lib", "entity")
        self.assertEqual(self.cfg.get_configurations(lib_scope),
                         [cfg(disable_ieee_warnings=False)])

        self.assertEqual(self.cfg.get_configurations(ent_scope),
                         [cfg(disable_ieee_warnings=False)])

        self.cfg.disable_ieee_warnings(ent_scope)
        self.assertEqual(self.cfg.get_configurations(lib_scope),
                         [cfg(disable_ieee_warnings=False)])

        self.assertEqual(self.cfg.get_configurations(ent_scope),
                         [cfg(disable_ieee_warnings=True)])

        self.cfg.disable_ieee_warnings(lib_scope)
        self.assertEqual(self.cfg.get_configurations(lib_scope),
                         [cfg(disable_ieee_warnings=True)])

        self.assertEqual(self.cfg.get_configurations(ent_scope),
                         [cfg(disable_ieee_warnings=True)])

    def test_more_specific_configurations(self):
        self.cfg.set_generic("name", "value", scope=create_scope("lib", "entity3"))
        self.cfg.set_generic("name", "value", scope=create_scope("lib", "entity", "test"))
        self.cfg.disable_ieee_warnings(scope=create_scope("lib", "entity_ieee", "test"))
        self.cfg.add_config(name="name", generics=dict(), scope=create_scope("lib", "entity2", "test"))
        self.cfg.set_sim_option("vsim_extra_args", "", scope=create_scope("lib", "entity4", "test"))
        self.assertEqual(self.cfg.more_specific_configurations(create_scope("lib", "entity")),
                         [create_scope("lib", "entity", "test")])
        self.assertEqual(self.cfg.more_specific_configurations(create_scope("lib", "entity2")),
                         [create_scope("lib", "entity2", "test")])
        self.assertEqual(self.cfg.more_specific_configurations(create_scope("lib", "entity3")),
                         [])
        self.assertEqual(self.cfg.more_specific_configurations(create_scope("lib", "entity4")),
                         [create_scope("lib", "entity4", "test")])
        self.assertEqual(self.cfg.more_specific_configurations(create_scope("lib", "entity_ieee")),
                         [create_scope("lib", "entity_ieee", "test")])

    def test_no_post_check_when_elaborate_only(self):
        self.cfg = TestConfiguration(elaborate_only=True)
        scope = create_scope("lib", "entity")

        def pre_config():
            return True

        def post_check():
            return True

        self.cfg.add_config(name="name",
                            generics=dict(),
                            pre_config=pre_config,
                            post_check=post_check,
                            scope=scope)

        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg("name", pre_config=pre_config, elaborate_only=True)])

    def test_config_with_post_check(self):
        scope = create_scope("lib", "entity")

        def post_check():
            return True

        self.cfg.add_config(name="name",
                            generics=dict(),
                            post_check=post_check,
                            scope=scope)

        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg("name", post_check=post_check)])

    def test_config_with_pre_config(self):
        scope = create_scope("lib", "entity")

        def pre_config():
            return True

        self.cfg.add_config(name="name",
                            generics=dict(),
                            pre_config=pre_config,
                            scope=scope)

        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg("name", pre_config=pre_config)])

    def test_sim_options(self):
        scope = create_scope("lib", "entity")
        sim_options = {"vsim_extra_args": "-voptargs=+acc"}

        for name, value in sim_options.items():
            self.cfg.set_sim_option(name=name,
                                    value=value,
                                    scope=scope)

        self.assertEqual(self.cfg.get_configurations(create_scope("lib")),
                         [cfg()])

        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(sim_options=sim_options)])

        self.assertEqual(self.cfg.get_configurations(create_scope("lib", "entity", "test")),
                         [cfg(sim_options=sim_options)])

    def test_fail_on_unknown_sim_option(self):
        self.assertRaises(ValueError, self.cfg.set_sim_option, "unknown", "value")

    def test_issue_65(self):
        self.cfg.set_generic(name="name", value=1, scope=create_scope())
        self.cfg.set_sim_option(name="vsim_extra_args", value="-quiet", scope=create_scope())

    @staticmethod
    def write_file(name, contents):
        with open(name, "w") as fwrite:
            fwrite.write(contents)
示例#10
0
class TestTestScanner(unittest.TestCase):
    """
    Tests the test scanner
    """

    def setUp(self):
        self.simulator_if = 'simulator_if'
        self.configuration = TestConfiguration()
        self.test_scanner = TestScanner(self.simulator_if, self.configuration)
        self.output_path = join(dirname(__file__), "test_scanner_out")
        renew_path(self.output_path)

    def tearDown(self):
        if exists(self.output_path):
            rmtree(self.output_path)

    def test_that_no_tests_are_created(self):
        project = ProjectStub()
        tests = self.test_scanner.from_project(project)
        self.assertEqual(len(tests), 0)

    def test_that_single_vhdl_test_is_created(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        lib.add_entity("tb_entity")
        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests, ["lib.tb_entity.all"])

    def test_that_single_verilog_test_is_created(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        lib.add_module("tb_module")
        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests, ["lib.tb_module.all"])

    def test_runner_cfg_creates_tests_from_entity(self):
        project = ProjectStub()
        lib = project.add_library("lib")

        lib.add_entity("entity_ok", generic_names=["runner_cfg"])
        lib.add_entity("entity_not_ok")

        tests = self.test_scanner.from_project(project, entity_filter=tb_filter)
        self.assert_has_tests(tests,
                              ["lib.entity_ok.all"])

    def test_runner_cfg_creates_tests_from_module(self):
        project = ProjectStub()
        lib = project.add_library("lib")

        lib.add_module("module_ok", generic_names=["runner_cfg"])
        lib.add_module("module_not_ok")

        tests = self.test_scanner.from_project(project, entity_filter=tb_filter)
        self.assert_has_tests(tests,
                              ["lib.module_ok.all"])

    def test_warning_on_missing_runner_cfg_when_matching_tb_pattern(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        module = lib.add_module("tb_module_not_ok")

        with mock.patch("vunit.test_scanner.LOGGER", autospec=True) as logger:
            tests = self.test_scanner.from_project(project, entity_filter=tb_filter)
            logger.warning.assert_has_calls([
                mock.call('%s %s matches testbench name regex %s '
                          'but has no %s runner_cfg and will therefore not be run.\n'
                          'in file %s',
                          'Module',
                          'tb_module_not_ok',
                          '(tb_.*)|(.*_tb)',
                          'parameter',
                          module.file_name)])
        self.assert_has_tests(tests, [])

    def test_warning_on_runner_cfg_but_not_matching_tb_pattern(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        entity = lib.add_entity("entity_ok_but_warning", generic_names=["runner_cfg"])

        with mock.patch("vunit.test_scanner.LOGGER", autospec=True) as logger:
            tests = self.test_scanner.from_project(project, entity_filter=tb_filter)
            logger.warning.assert_has_calls([
                mock.call('%s %s has runner_cfg %s but the file name and the %s name does not match regex %s\n'
                          'in file %s',
                          'Entity',
                          'entity_ok_but_warning',
                          'generic',
                          'entity',
                          '(tb_.*)|(.*_tb)',
                          entity.file_name)])
        self.assert_has_tests(tests, ["lib.entity_ok_but_warning.all"])

    def test_that_two_tests_are_created_from_two_architectures(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        ent = lib.add_entity("tb_entity")
        ent.add_architecture("arch2")

        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests,
                              ["lib.tb_entity.arch.all",
                               "lib.tb_entity.arch2.all"])

    def test_create_tests_with_runner_cfg_generic(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        lib.add_entity("tb_entity",
                       generic_names=["runner_cfg"],
                       contents='''\
if run("Test_1")
--if run("Test_2")
if run("Test_3")
''')

        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests,
                              ["lib.tb_entity.Test_1",
                               "lib.tb_entity.Test_3"])

    @mock.patch("vunit.test_scanner.LOGGER")
    def test_duplicate_tests_cause_error(self, mock_logger):
        project = ProjectStub()
        lib = project.add_library("lib")
        ent = lib.add_entity("tb_entity",
                             generic_names=["runner_cfg"],
                             contents='''\
if run("Test_1")
--if run("Test_1")
if run("Test_3")
if run("Test_2")
if run("Test_3")
if run("Test_3")
if run("Test_2")
''')

        self.assertRaises(TestScannerError, self.test_scanner.from_project, project)

        error_calls = mock_logger.error.call_args_list
        self.assertEqual(len(error_calls), 2)
        call0_args = error_calls[0][0]
        self.assertIn("Test_3", call0_args)
        self.assertIn(ent.file_name, call0_args)

        call1_args = error_calls[1][0]
        self.assertIn("Test_2", call1_args)
        self.assertIn(ent.file_name, call1_args)

    @mock.patch("vunit.test_scanner.LOGGER")
    def test_warning_on_configuration_of_non_existent_test(self, mock_logger):
        project = ProjectStub()
        lib = project.add_library("lib")
        lib.add_entity("tb_entity",
                       generic_names=["runner_cfg", "name"],
                       contents='if run("Test")')

        test_scope = create_scope("lib", "tb_entity", "Test")
        self.configuration.set_generic("name", "value",
                                       scope=test_scope)

        test_1_scope = create_scope("lib", "tb_entity", "No test 1")
        self.configuration.add_config(scope=test_1_scope,
                                      name="",
                                      generics=dict())

        test_2_scope = create_scope("lib", "tb_entity", "No test 2")
        self.configuration.set_generic("name", "value",
                                       scope=test_2_scope)

        tests = self.test_scanner.from_project(project)

        warning_calls = mock_logger.warning.call_args_list
        self.assertEqual(len(warning_calls), 2)
        call_args0 = warning_calls[0][0]
        call_args1 = warning_calls[1][0]
        self.assertIn(dotjoin(*test_1_scope), call_args0)
        self.assertIn(dotjoin(*test_2_scope), call_args1)
        self.assert_has_tests(tests,
                              ["lib.tb_entity.Test"])

    @mock.patch("vunit.test_scanner.LOGGER")
    def test_warning_on_configuration_of_individual_test_with_same_sim(self, mock_logger):
        project = ProjectStub()
        lib = project.add_library("lib")
        lib.add_entity("tb_entity",
                       generic_names=["runner_cfg"],
                       contents='''\
if run("Test 1")
if run("Test 2")
-- vunit_pragma run_all_in_same_sim
''')

        test_scope = create_scope("lib", "tb_entity", "Test 1")
        self.configuration.set_generic("name", "value", scope=test_scope)
        tests = self.test_scanner.from_project(project)

        warning_calls = mock_logger.warning.call_args_list
        self.assertEqual(len(warning_calls), 1)
        call_args = warning_calls[0][0]
        self.assertIn(1, call_args)
        self.assertIn("lib.tb_entity", call_args)
        self.assert_has_tests(tests,
                              [("lib.tb_entity", ("lib.tb_entity.Test 1", "lib.tb_entity.Test 2"))])

    def test_create_default_test_with_runner_cfg_generic(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        lib.add_entity("tb_entity",
                       generic_names=["runner_cfg"])

        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests,
                              ["lib.tb_entity.all"])

    def test_does_not_add_all_suffix_with_named_configurations(self):

        def helper(config_name, suffix):
            """
            Add config with name and check that the test has the given suffix
            """
            project = ProjectStub()
            lib = project.add_library("lib")
            lib.add_entity("tb_entity",
                           generic_names=["runner_cfg"])
            self.configuration = TestConfiguration()
            self.test_scanner = TestScanner(self.simulator_if, self.configuration)
            self.configuration.add_config(scope=create_scope("lib", "tb_entity"),
                                          name=config_name,
                                          generics=dict())
            tests = self.test_scanner.from_project(project)
            self.assert_has_tests(tests,
                                  ["lib.tb_entity" + suffix])
        helper("config", ".config")
        helper("", ".all")
        helper(None, ".all")

    def test_that_pragma_run_in_same_simulation_works(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        lib.add_entity("tb_entity",
                       generic_names=["runner_cfg"],
                       contents='''\
-- vunit_pragma run_all_in_same_sim
if run("Test_1")
if run("Test_2")
--if run("Test_3")
''')

        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests,
                              [("lib.tb_entity", ("lib.tb_entity.Test_1", "lib.tb_entity.Test_2"))])

    def test_adds_tb_path_generic(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        lib.add_entity("tb_entity_with_tb_path",
                       generic_names=["tb_path"])

        lib.add_entity("tb_entity_without_tb_path")

        tests = self.test_scanner.from_project(project)

        with_path_generics = find_generics(tests, "lib.tb_entity_with_tb_path.all")
        without_path_generics = find_generics(tests, "lib.tb_entity_without_tb_path.all")
        self.assertEqual(with_path_generics["tb_path"], (out() + "/").replace("\\", "/"))
        self.assertNotIn("tb_path", without_path_generics)

    @mock.patch("vunit.test_scanner.LOGGER")
    def test_warning_on_non_overrriden_tb_path(self, mock_logger):
        project = ProjectStub()
        lib = project.add_library("lib")

        lib.add_entity("tb_entity",
                       generic_names=["tb_path"])

        tb_path_non_overriden_value = "foo"
        self.configuration.set_generic("tb_path", tb_path_non_overriden_value)
        tests = self.test_scanner.from_project(project)

        warning_calls = mock_logger.warning.call_args_list
        tb_path_value = (out() + "/").replace("\\", "/")
        self.assertEqual(len(warning_calls), 1)
        call_args = warning_calls[0][0]
        self.assertIn("lib.tb_entity", call_args)
        self.assertIn(tb_path_non_overriden_value, call_args)
        self.assertIn(tb_path_value, call_args)
        generics = find_generics(tests, "lib.tb_entity.all")
        self.assertEqual(generics["tb_path"], tb_path_value)

    @mock.patch("vunit.test_scanner.LOGGER")
    def test_warning_on_setting_missing_generic(self, mock_logger):
        project = ProjectStub()
        lib = project.add_library("lib")

        lib.add_entity("tb_entity",
                       generic_names=[""])
        self.configuration.set_generic("name123", "value123")
        self.test_scanner.from_project(project)
        warning_calls = mock_logger.warning.call_args_list
        self.assertEqual(len(warning_calls), 1)
        call_args = warning_calls[0][0]
        self.assertIn("lib", call_args)
        self.assertIn("tb_entity", call_args)
        self.assertIn("name123", call_args)
        self.assertIn("value123", call_args)

    def assert_has_tests(self, test_list, tests):
        """
        Asser that the test_list contains tests.
        A test can be either a string to represent a single test or a
        tuple to represent multiple tests within a test suite.
        """
        self.assertEqual(len(test_list), len(tests))
        for test1, test2 in zip(test_list, sorted(tests)):
            if isinstance(test2, tuple):
                name, test_cases = test2
                self.assertEqual(test1.name, name)
                self.assertEqual(test1.test_cases, list(test_cases))
            else:
                self.assertEqual(test1.name, test2)
class TestTestConfiguration(unittest.TestCase):

    def setUp(self):
        self.cfg = TestConfiguration()

        self.output_path = out()
        if exists(self.output_path):
            rmtree(self.output_path)
        makedirs(self.output_path)

    def test_has_default_configuration(self):
        entity = EntityStub()
        entity.name = "tb_entity"
        entity.library_name = "lib"
        entity.architecture_names = {"arch" : out("arch.vhd")}
        entity.generic_names = []

        self.assertEqual(self.cfg.get_configurations(entity, "arch"),
                         [Configuration("lib.tb_entity")])

    def test_set_generic(self):
        entity = EntityStub()
        entity.name = "tb_entity"
        entity.library_name = "lib"
        entity.architecture_names = {"arch" : out("arch.vhd")}
        entity.generic_names = ["global_generic"]

        self.assertEqual(self.cfg.get_configurations(entity, "arch"),
                         [Configuration("lib.tb_entity")])

        self.cfg.set_generic("global_generic", False, scope="")
        self.assertEqual(self.cfg.get_configurations(entity, "arch"),
                         [Configuration("lib.tb_entity", generics={"global_generic" : False})])

        self.cfg.set_generic("global_generic", True, scope="lib")
        self.cfg.set_generic("generic_not_present", True, scope="lib")
        self.assertEqual(self.cfg.get_configurations(entity, "arch"),
                         [Configuration("lib.tb_entity", generics={"global_generic" : True})])

        self.cfg.set_generic("global_generic", None, scope="lib.tb_entity")
        self.assertEqual(self.cfg.get_configurations(entity, "arch"),
                         [Configuration("lib.tb_entity", generics={"global_generic" : None})])

    def test_set_pli(self):
        entity = EntityStub()
        entity.name = "tb_entity"
        entity.library_name = "lib"
        entity.architecture_names = {"arch" : out("arch.vhd")}
        entity.generic_names = []

        self.assertEqual(self.cfg.get_configurations(entity, "arch"),
                         [Configuration("lib.tb_entity")])

        self.cfg.set_pli(["libglobal.so"], scope="")
        self.cfg.set_pli(["libfoo.so"], scope="lib2")
        self.assertEqual(self.cfg.get_configurations(entity, "arch"),
                         [Configuration("lib.tb_entity", pli=["libglobal.so"])])

        self.cfg.set_pli(["libfoo.so"], scope="lib")
        self.assertEqual(self.cfg.get_configurations(entity, "arch"),
                         [Configuration("lib.tb_entity", pli=["libfoo.so"])])

        self.cfg.set_pli(["libfoo2.so"], scope="lib.tb_entity")
        self.assertEqual(self.cfg.get_configurations(entity, "arch"),
                         [Configuration("lib.tb_entity", pli=["libfoo2.so"])])

    def test_add_config(self):
        entity = EntityStub()
        entity.name = "tb_entity"
        entity.library_name = "lib"
        entity.architecture_names = {"arch" : out("arch.vhd")}
        entity.generic_names = ["value",
                                "global_value"]

        for value in range(1, 3):
            self.cfg.add_config("lib.tb_entity",
                                name="value=%i" % value,
                                generics=dict(value=value,
                                              global_value="local value"))

        # Local value should take precedence
        self.cfg.set_generic("global_value", "global value")

        self.assertEqual(self.cfg.get_configurations(entity, "arch"),
                         [Configuration("lib.tb_entity.value=1",
                                        generics={"value" : 1, "global_value" : "local value"}),
                          Configuration("lib.tb_entity.value=2",
                                        generics={"value" : 2, "global_value" : "local value"})])

    def write_file(self, name, contents):
        with open(name, "w") as fwrite:
            fwrite.write(contents)
示例#12
0
    def setUp(self):
        self.cfg = TestConfiguration()

        self.output_path = out()
        renew_path(self.output_path)
示例#13
0
class TestTestConfiguration(unittest.TestCase):
    """
    Test the global test bench configuration
    """
    def setUp(self):
        self.cfg = TestConfiguration()

        self.output_path = out()
        renew_path(self.output_path)

    def test_has_default_configuration(self):
        scope = create_scope("lib", "tb_entity")
        self.assertEqual(self.cfg.get_configurations(scope), [cfg()])

    def test_set_generic(self):
        scope = create_scope("lib", "tb_entity")
        self.assertEqual(self.cfg.get_configurations(scope), [cfg()])

        self.cfg.set_generic("global_generic", "global", scope=create_scope())
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(generics={"global_generic": "global"})])

        self.cfg.set_generic("global_generic",
                             "library",
                             scope=create_scope("lib"))
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(generics={"global_generic": "library"})])

        self.cfg.set_generic("global_generic",
                             "entity",
                             scope=create_scope("lib", "tb_entity"))
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(generics={"global_generic": "entity"})])

    def test_set_pli(self):
        scope = create_scope("lib", "tb_entity")
        self.assertEqual(self.cfg.get_configurations(scope), [cfg("")])

        self.cfg.set_pli(["libglobal.so"], scope=create_scope())
        self.cfg.set_pli(["libfoo.so"], scope=create_scope("lib2"))
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(pli=["libglobal.so"])])

        self.cfg.set_pli(["libfoo.so"], scope=create_scope("lib"))
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(pli=["libfoo.so"])])

        self.cfg.set_pli(["libfoo2.so"],
                         scope=create_scope("lib", "tb_entity"))
        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(pli=["libfoo2.so"])])

    def test_add_config(self):
        for value in range(1, 3):
            self.cfg.add_config(scope=create_scope("lib", "tb_entity"),
                                name="value=%i" % value,
                                generics=dict(value=value,
                                              global_value="local value"))

        self.cfg.add_config(scope=create_scope("lib", "tb_entity",
                                               "configured test"),
                            name="specific_test_config",
                            generics=dict())

        # Local value should take precedence
        self.cfg.set_generic("global_value", "global value")

        self.assertEqual(
            self.cfg.get_configurations(create_scope("lib", "tb_entity")), [
                cfg("value=1",
                    generics={
                        "value": 1,
                        "global_value": "local value"
                    }),
                cfg("value=2",
                    generics={
                        "value": 2,
                        "global_value": "local value"
                    })
            ])

        self.assertEqual(
            self.cfg.get_configurations(
                create_scope("lib", "tb_entity", "test")), [
                    cfg("value=1",
                        generics={
                            "value": 1,
                            "global_value": "local value"
                        }),
                    cfg("value=2",
                        generics={
                            "value": 2,
                            "global_value": "local value"
                        })
                ])

        self.assertEqual(
            self.cfg.get_configurations(
                create_scope("lib", "tb_entity", "configured test")),
            [cfg("specific_test_config", dict(global_value="global value"))])

    def test_disable_ieee_warnings(self):
        lib_scope = create_scope("lib")
        ent_scope = create_scope("lib", "entity")
        self.assertEqual(self.cfg.get_configurations(lib_scope),
                         [cfg(disable_ieee_warnings=False)])

        self.assertEqual(self.cfg.get_configurations(ent_scope),
                         [cfg(disable_ieee_warnings=False)])

        self.cfg.disable_ieee_warnings(ent_scope)
        self.assertEqual(self.cfg.get_configurations(lib_scope),
                         [cfg(disable_ieee_warnings=False)])

        self.assertEqual(self.cfg.get_configurations(ent_scope),
                         [cfg(disable_ieee_warnings=True)])

        self.cfg.disable_ieee_warnings(lib_scope)
        self.assertEqual(self.cfg.get_configurations(lib_scope),
                         [cfg(disable_ieee_warnings=True)])

        self.assertEqual(self.cfg.get_configurations(ent_scope),
                         [cfg(disable_ieee_warnings=True)])

    def test_more_specific_configurations(self):
        self.cfg.set_generic("name",
                             "value",
                             scope=create_scope("lib", "entity3"))
        self.cfg.set_generic("name",
                             "value",
                             scope=create_scope("lib", "entity", "test"))
        self.cfg.disable_ieee_warnings(
            scope=create_scope("lib", "entity_ieee", "test"))
        self.cfg.add_config(name="name",
                            generics=dict(),
                            scope=create_scope("lib", "entity2", "test"))
        self.cfg.set_sim_option("ghdl.flags", [],
                                scope=create_scope("lib", "entity4", "test"))
        self.assertEqual(
            self.cfg.more_specific_configurations(create_scope(
                "lib", "entity")), [create_scope("lib", "entity", "test")])
        self.assertEqual(
            self.cfg.more_specific_configurations(
                create_scope("lib", "entity2")),
            [create_scope("lib", "entity2", "test")])
        self.assertEqual(
            self.cfg.more_specific_configurations(
                create_scope("lib", "entity3")), [])
        self.assertEqual(
            self.cfg.more_specific_configurations(
                create_scope("lib", "entity4")),
            [create_scope("lib", "entity4", "test")])
        self.assertEqual(
            self.cfg.more_specific_configurations(
                create_scope("lib", "entity_ieee")),
            [create_scope("lib", "entity_ieee", "test")])

    def test_config_with_post_check(self):
        scope = create_scope("lib", "entity")

        def post_check():
            return True

        self.cfg.add_config(name="name",
                            generics=dict(),
                            post_check=post_check,
                            scope=scope)

        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg("name", post_check=post_check)])

    def test_config_with_pre_config(self):
        scope = create_scope("lib", "entity")

        def pre_config():
            return True

        self.cfg.add_config(name="name",
                            generics=dict(),
                            pre_config=pre_config,
                            scope=scope)

        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg("name", pre_config=pre_config)])

    def test_sim_options(self):
        scope = create_scope("lib", "entity")
        sim_options = {"modelsim.vsim_flags": "-voptargs=+acc"}

        for name, value in sim_options.items():
            self.cfg.set_sim_option(name=name, value=value, scope=scope)

        self.assertEqual(self.cfg.get_configurations(create_scope("lib")),
                         [cfg()])

        self.assertEqual(self.cfg.get_configurations(scope),
                         [cfg(sim_options=sim_options)])

        self.assertEqual(
            self.cfg.get_configurations(create_scope("lib", "entity", "test")),
            [cfg(sim_options=sim_options)])

    def test_fail_on_unknown_sim_option(self):
        self.assertRaises(ValueError, self.cfg.set_sim_option, "unknown",
                          "value")

    def test_issue_65(self):
        self.cfg.set_generic(name="name", value=1, scope=create_scope())
        self.cfg.set_sim_option(name="modelsim.vsim_flags",
                                value="-quiet",
                                scope=create_scope())

    @staticmethod
    def write_file(name, contents):
        with open(name, "w") as fwrite:
            fwrite.write(contents)
示例#14
0
 def setUp(self):
     self.simulator_if = 'simulator_if'
     self.configuration = TestConfiguration()
     self.test_scanner = TestScanner(self.simulator_if, self.configuration)
     self.output_path = join(dirname(__file__), "test_scanner_out")
     renew_path(self.output_path)
    def setUp(self):
        self.cfg = TestConfiguration()

        self.output_path = out()
        renew_path(self.output_path)
示例#16
0
 def setUp(self):
     self.simulator_if = 'simulator_if'
     self.configuration = TestConfiguration()
     self.test_scanner = TestScanner(self.simulator_if, self.configuration)
     self.output_path = join(dirname(__file__), "test_scanner_out")
     renew_path(self.output_path)
示例#17
0
class TestTestScanner(unittest.TestCase):
    """
    Tests the test scanner
    """

    def setUp(self):
        self.simulator_if = 'simulator_if'
        self.configuration = TestConfiguration()
        self.test_scanner = TestScanner(self.simulator_if, self.configuration)
        self.output_path = join(dirname(__file__), "test_scanner_out")
        renew_path(self.output_path)

    def tearDown(self):
        if exists(self.output_path):
            rmtree(self.output_path)

    def test_that_no_tests_are_created(self):
        project = ProjectStub()
        tests = self.test_scanner.from_project(project)
        self.assertEqual(len(tests), 0)

    def test_that_single_vhdl_test_is_created(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        ent = lib.add_entity("tb_entity")
        ent.set_contents("")
        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests, ["lib.tb_entity"])

    def test_that_single_verilog_test_is_created(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        module = lib.add_module("tb_module")
        module.set_contents("")
        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests, ["lib.tb_module"])

    def test_that_tests_are_filtered(self):
        project = ProjectStub()
        lib = project.add_library("lib")

        tb1 = lib.add_entity("tb_entity")
        tb1.set_contents("")

        tb2 = lib.add_entity("tb_entity2")
        tb2.set_contents("")

        ent = lib.add_entity("entity_tb")
        ent.set_contents("")

        ent2 = lib.add_entity("entity2")
        ent2.set_contents("")

        tests = self.test_scanner.from_project(project, entity_filter=tb_filter)
        self.assert_has_tests(tests,
                              ["lib.entity_tb",
                               "lib.tb_entity",
                               "lib.tb_entity2"])

    def test_that_two_tests_are_created_from_two_architectures(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        ent = lib.add_entity("tb_entity")
        ent.set_contents("")

        arch2 = ent.add_architecture("arch2")
        arch2.set_contents("")

        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests,
                              ["lib.tb_entity.arch",
                               "lib.tb_entity.arch2"])

    def test_create_tests_with_runner_cfg_generic(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        ent = lib.add_entity("tb_entity",
                             generic_names=["runner_cfg"])

        ent.set_contents('''\
if run("Test_1")
--if run("Test_2")
if run("Test_3")
''')

        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests,
                              ["lib.tb_entity.Test_1",
                               "lib.tb_entity.Test_3"])

    @mock.patch("vunit.test_scanner.LOGGER")
    def test_duplicate_tests_cause_error(self, mock_logger):
        project = ProjectStub()
        lib = project.add_library("lib")
        ent = lib.add_entity("tb_entity",
                             generic_names=["runner_cfg"])

        ent.set_contents('''\
if run("Test_1")
--if run("Test_1")
if run("Test_3")
if run("Test_2")
if run("Test_3")
if run("Test_3")
if run("Test_2")
''')

        self.assertRaises(TestScannerError, self.test_scanner.from_project, project)

        error_calls = mock_logger.error.call_args_list
        self.assertEqual(len(error_calls), 2)
        call0_args = error_calls[0][0]
        self.assertIn("Test_3", call0_args)
        self.assertIn(ent.file_name, call0_args)

        call1_args = error_calls[1][0]
        self.assertIn("Test_2", call1_args)
        self.assertIn(ent.file_name, call1_args)

    @mock.patch("vunit.test_scanner.LOGGER")
    def test_warning_on_configuration_of_non_existent_test(self, mock_logger):
        project = ProjectStub()
        lib = project.add_library("lib")
        ent = lib.add_entity("tb_entity",
                             generic_names=["runner_cfg", "name"])

        ent.set_contents('if run("Test")')

        test_scope = create_scope("lib", "tb_entity", "Test")
        self.configuration.set_generic("name", "value",
                                       scope=test_scope)

        test_1_scope = create_scope("lib", "tb_entity", "No test 1")
        self.configuration.add_config(scope=test_1_scope,
                                      name="",
                                      generics=dict())

        test_2_scope = create_scope("lib", "tb_entity", "No test 2")
        self.configuration.set_generic("name", "value",
                                       scope=test_2_scope)

        tests = self.test_scanner.from_project(project)

        warning_calls = mock_logger.warning.call_args_list
        self.assertEqual(len(warning_calls), 2)
        call_args0 = warning_calls[0][0]
        call_args1 = warning_calls[1][0]
        self.assertIn(dotjoin(*test_1_scope), call_args0)
        self.assertIn(dotjoin(*test_2_scope), call_args1)
        self.assert_has_tests(tests,
                              ["lib.tb_entity.Test"])

    @mock.patch("vunit.test_scanner.LOGGER")
    def test_warning_on_configuration_of_individual_test_with_same_sim(self, mock_logger):
        project = ProjectStub()
        lib = project.add_library("lib")
        ent = lib.add_entity("tb_entity",
                             generic_names=["runner_cfg"])

        ent.set_contents('''\
if run("Test 1")
if run("Test 2")
-- vunit_pragma run_all_in_same_sim
''')

        test_scope = create_scope("lib", "tb_entity", "Test 1")
        self.configuration.set_generic("name", "value", scope=test_scope)
        tests = self.test_scanner.from_project(project)

        warning_calls = mock_logger.warning.call_args_list
        self.assertEqual(len(warning_calls), 1)
        call_args = warning_calls[0][0]
        self.assertIn(1, call_args)
        self.assertIn("lib.tb_entity", call_args)
        self.assert_has_tests(tests,
                              [("lib.tb_entity", ("lib.tb_entity.Test 1", "lib.tb_entity.Test 2"))])

    def test_create_default_test_with_runner_cfg_generic(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        ent = lib.add_entity("tb_entity",
                             generic_names=["runner_cfg"])

        ent.set_contents('')

        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests,
                              ["lib.tb_entity"])

    def test_that_pragma_run_in_same_simulation_works(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        ent = lib.add_entity("tb_entity",
                             generic_names=["runner_cfg"])

        ent.set_contents('''\
-- vunit_pragma run_all_in_same_sim
if run("Test_1")
if run("Test_2")
--if run("Test_3")
''')

        tests = self.test_scanner.from_project(project)
        self.assert_has_tests(tests,
                              [("lib.tb_entity", ("lib.tb_entity.Test_1", "lib.tb_entity.Test_2"))])

    def test_adds_tb_path_generic(self):
        project = ProjectStub()
        lib = project.add_library("lib")
        with_path = lib.add_entity("tb_entity_with_tb_path",
                                   generic_names=["tb_path"])
        with_path.set_contents("")

        without_path = lib.add_entity("tb_entity_without_tb_path")
        without_path.set_contents("")

        tests = self.test_scanner.from_project(project)

        with_path_generics = find_generics(tests, "lib.tb_entity_with_tb_path")
        without_path_generics = find_generics(tests, "lib.tb_entity_without_tb_path")
        self.assertEqual(with_path_generics["tb_path"], (out() + "/").replace("\\", "/"))
        self.assertNotIn("tb_path", without_path_generics)

    @mock.patch("vunit.test_scanner.LOGGER")
    def test_warning_on_non_overrriden_tb_path(self, mock_logger):
        project = ProjectStub()
        lib = project.add_library("lib")

        ent = lib.add_entity("tb_entity",
                             generic_names=["tb_path"])
        ent.set_contents("")

        tb_path_non_overriden_value = "foo"
        self.configuration.set_generic("tb_path", tb_path_non_overriden_value)
        tests = self.test_scanner.from_project(project)

        warning_calls = mock_logger.warning.call_args_list
        tb_path_value = (out() + "/").replace("\\", "/")
        self.assertEqual(len(warning_calls), 1)
        call_args = warning_calls[0][0]
        self.assertIn("lib.tb_entity", call_args)
        self.assertIn(tb_path_non_overriden_value, call_args)
        self.assertIn(tb_path_value, call_args)
        generics = find_generics(tests, "lib.tb_entity")
        self.assertEqual(generics["tb_path"], tb_path_value)

    @mock.patch("vunit.test_scanner.LOGGER")
    def test_warning_on_setting_missing_generic(self, mock_logger):
        project = ProjectStub()
        lib = project.add_library("lib")

        ent = lib.add_entity("tb_entity",
                             generic_names=[""])
        ent.set_contents("")
        self.configuration.set_generic("name123", "value123")
        self.test_scanner.from_project(project)
        warning_calls = mock_logger.warning.call_args_list
        self.assertEqual(len(warning_calls), 1)
        call_args = warning_calls[0][0]
        self.assertIn("lib", call_args)
        self.assertIn("tb_entity", call_args)
        self.assertIn("name123", call_args)
        self.assertIn("value123", call_args)

    def assert_has_tests(self, test_list, tests):
        """
        Asser that the test_list contains tests.
        A test can be either a string to represent a single test or a
        tuple to represent multiple tests within a test suite.
        """
        self.assertEqual(len(test_list), len(tests))
        for test1, test2 in zip(test_list, tests):
            if isinstance(test2, tuple):
                name, test_cases = test2
                self.assertEqual(test1.name, name)
                self.assertEqual(test1.test_cases, list(test_cases))
            else:
                self.assertEqual(test1.name, test2)
示例#18
0
class VUnit:
    """
    The public interface of VUnit
    """

    _builtin_vhdl_path = abspath(join(dirname(__file__), "..", "vhdl"))

    @classmethod
    def from_argv(cls, argv=None):
        """
        Create VUnit instance from command line arguments
        Can take arguments from 'argv' if not None  instead of sys.argv
        """
        parser = cls._create_argument_parser()
        args = parser.parse_args(args=argv)

        def test_filter(name):
            return any(fnmatch(name, pattern) for pattern in args.test_patterns)

        return cls(output_path=args.output_path,
                   clean=args.clean,
                   no_color=args.no_color,
                   verbose=args.verbose,
                   xunit_xml=args.xunit_xml,
                   log_level=args.log_level,
                   test_filter=test_filter,
                   list_only=args.list,
                   compile_only=args.compile,
                   gui=args.gui)

    @classmethod
    def _create_argument_parser(cls):
        parser = argparse.ArgumentParser(description='VUnit command line tool.')

        parser.add_argument('test_patterns', metavar='tests', nargs='*',
                            default='*',
                            help='Tests to run')

        parser.add_argument('-l', '--list', action='store_true',
                           default=False,
                           help='Only list all test cases')

        parser.add_argument('--compile', action='store_true',
                           default=False,
                           help='Only compile project')

        parser.add_argument('--clean', action='store_true',
                           default=False,
                           help='Remove output path first')

        parser.add_argument('-o', '--output-path',
                           default=join(abspath(getcwd()), "vunit_out"),
                           help='Output path for compilation and simulation artifacts')

        parser.add_argument('-x', '--xunit-xml',
                           default=None,
                           help='Xunit test report .xml file')

        parser.add_argument('-v', '--verbose', action="store_true",
                           default=False,
                           help='Print test output immediately and not only when failure')

        parser.add_argument('--no-color', action='store_true',
                           default=False,
                           help='Do not color output')

        parser.add_argument('--gui', action='store_true',
                           default=False,
                           help='Open test case(s) in simulator gui')

        parser.add_argument('--log-level',
                            default="warning",
                            choices=["info", "error", "warning", "debug"])

        return parser

    def __init__(self,
                 output_path,
                 clean=False,
                 no_color=False,
                 verbose=False,
                 xunit_xml=None,
                 log_level="warning",
                 test_filter=None,
                 list_only=False,
                 compile_only=False,
                 elaborate_only=False,
                 vhdl_standard='2008',
                 compile_builtins=True,
                 persistent_sim=True,
                 gui=False):

        self._project = Project()

        self._output_path = output_path
        self._clean = clean

        if no_color:
            self._printer = NoColorPrinter
        else:
            self._printer = ColorPrinter

        self._verbose = verbose
        self._xunit_xml = xunit_xml

        level = getattr(logging, log_level.upper())
        logging.basicConfig(filename=None, format='%(levelname)7s - %(message)s', level=level)

        self._test_filter = test_filter if test_filter is not None else lambda name : True
        self._list_only = list_only
        self._compile_only = compile_only
        self._elaborate_only = elaborate_only
        self._vhdl_standard = vhdl_standard

        self._tb_filter = tb_filter
        self._persistent_sim = persistent_sim
        self._gui = gui
        self._configuration = TestConfiguration()
        self._external_preprocessors = []
        self._location_preprocessor = None
        self._check_preprocessor = None

        self._create_output_path()

        if compile_builtins:
            self.add_builtins(library_name="vunit_lib")

    def add_external_library(self, library_name, path):
        """
        Add external black box library
        """
        self._project.add_library(library_name, abspath(path), is_external=True)
        return LibraryFacade(library_name, self)

    def add_library(self, library_name):
        """
        Add vunit managed white box library
        """
        path = join(self._output_path, "libraries", library_name)
        self._project.add_library(library_name, abspath(path))
        return LibraryFacade(library_name, self)

    def library(self, library_name):
        """
        Get reference to library
        """
        if not library_name in self._project._libraries:
            raise KeyError(library_name)
        return LibraryFacade(library_name, self)

    def set_generic(self, name, value):
        " Globally set generic "
        self._configuration.set_generic(name, value, scope="")

    def set_pli(self, value):
        " Globally set pli "
        self._configuration.set_generic(value, scope="")

    def add_source_files(self, pattern, library_name, preprocessors=None):
        """
        Add source files matching wildcard pattern to library
        """

        for file_name in glob(pattern):
            file_name = self._preprocess(library_name, abspath(file_name), preprocessors)
            self._project.add_source_file(file_name,
                                          library_name,
                                          file_type=file_type_of(file_name))

    def _preprocess(self, library_name, file_name, preprocessors):
        # @TODO dependency checking etc...

        if preprocessors is None:
            preprocessors = [self._location_preprocessor, self._check_preprocessor]
            preprocessors = [p for p in preprocessors if not p is None]
            preprocessors = self._external_preprocessors + preprocessors

        if len(preprocessors) == 0:
            return file_name

        code = ostools.read_file(file_name)
        for p in preprocessors:
            code = p.run(code, basename(file_name))

        pp_file_name = join(self._preprocessed_path, library_name, basename(file_name))

        idx = 1
        while ostools.file_exists(pp_file_name):
            logger.debug("Preprocessed file exists '%s', adding prefix" % pp_file_name)
            pp_file_name = join(self._preprocessed_path,
                                library_name, "%i_%s" % (idx, basename(file_name)))
            idx += 1

        ostools.write_file(pp_file_name, code)
        return pp_file_name

    def add_preprocessor(self, preprocessor):
        """
        Add a custom preprocessor to be used on all files, must be called before adding any files
        """
        self._external_preprocessors.append(preprocessor)

    def enable_location_preprocessing(self, additional_subprograms=None):
        """
        Enable location preprocessing, must be called before adding any files
        """
        p = LocationPreprocessor()
        if not additional_subprograms is None:
            for subprogram in additional_subprograms:
                p.add_subprogram(subprogram)
        self._location_preprocessor = p

    def enable_check_preprocessing(self):
        """
        Enable check preprocessing, must be called before adding any files
        """
        self._check_preprocessor = CheckPreprocessor()

    def main(self):
        """
        Run vunit main function and exit with code
        """
        try:
            all_ok = self._main()
        except KeyboardInterrupt:
            # Ctrl-C
            exit(1)
        except CompileError:
            exit(1)
        except TestScannerError:
            exit(1)
        except:
            traceback.print_exc()
            exit(1)

        if not all_ok:
            exit(1)

        exit(0)

    def _main(self):
        if self._list_only:
            return self._main_list_only()

        if self._compile_only:
            return self._main_compile_only()

        simulator_if = self._create_simulator_if()
        test_cases = self._create_tests(simulator_if)
        self._compile(simulator_if)

        report = self._run_test(test_cases)
        del simulator_if
        self._post_process(report)
        return report.all_ok()

    def _main_list_only(self):
        simulator_if = None
        test_suites = self._create_tests(simulator_if)
        num_tests = 0
        for test_suite in test_suites:
            for name in test_suite.test_cases:
                print(name)
                num_tests += 1
        print("Listed %i tests" % num_tests)
        return True

    def _main_compile_only(self):
        simulator_if = self._create_simulator_if()
        self._compile(simulator_if)
        return True

    def _create_output_path(self):
        if self._clean and exists(self._output_path):
            rmtree(self._output_path)

        if exists(self._preprocessed_path):
            rmtree(self._preprocessed_path)

        if not exists(self._output_path):
            makedirs(self._output_path)

    def _create_simulator_if(self):
        return ModelSimInterface(
            join(self._output_path, "modelsim.ini"),
            persistent=self._persistent_sim and not self._gui,
            gui=self._gui)

    @property
    def _preprocessed_path(self):
        return join(self._output_path, "preprocessed")

    def _create_tests(self, simulator_if):
        scanner = TestScanner(simulator_if,
                              self._configuration,
                              elaborate_only=self._elaborate_only)
        test_list = scanner.from_project(self._project, entity_filter=self._tb_filter)
        test_list.keep_matches(self._test_filter)
        return test_list

    def _compile(self, simulator_if):
        simulator_if.compile_project(self._project, self._vhdl_standard)

    def _run_test(self, test_cases):
        report = TestReport(printer=self._printer)
        runner = TestRunner(report,
                            join(self._output_path, "tests"),
                            verbose=self._verbose)
        runner.run(test_cases)
        return report

    def _post_process(self, report):
        report.print_str()

        if not self._xunit_xml is None:
            xml = report.to_junit_xml_str()
            ostools.write_file(self._xunit_xml, xml)

    def add_builtins(self, library_name, mock_lang=False, mock_log=False):
        files = []

        if mock_lang:
            files += [join("vhdl", "src", "lang", "lang_mock.vhd")]
        else:
            files += [join("vhdl", "src", "lang", "lang.vhd")]

        files += [join("vhdl", "src", "lib", "std", "textio.vhd"),
                  join("string_ops", "src", "string_ops.vhd"),
                  join("check", "src", "check.vhd"),
                  join("check", "src", "check_api.vhd"),
                  join("check", "src", "check_base_api.vhd"),
                  join("check", "src", "check_types.vhd"),
                  join("run", "src", "run.vhd"),
                  join("run", "src", "run_api.vhd"),
                  join("run", "src", "run_types.vhd"),
                  join("run", "src", "run_base_api.vhd")]

        files +=  [join("logging", "src", "log_api.vhd"),
                   join("logging", "src", "log_formatting.vhd"),
                   join("logging", "src", "log.vhd"),
                   join("logging", "src", "log_types.vhd")]

        files +=  [join("dictionary", "src", "dictionary.vhd")]

        files +=  [join("path", "src", "path.vhd")]

        if self._vhdl_standard == '93':
            if mock_log:
                files += [join("logging", "src", "log_base93_mock.vhd"),
                          join("logging", "src", "log_special_types93.vhd"),
                          join("logging", "src", "log_base_api_mock.vhd")]
            else:
                files += [join("logging", "src", "log_base93.vhd"),
                          join("logging", "src", "log_special_types93.vhd"),
                          join("logging", "src", "log_base_api.vhd")]

            files += [join("check", "src", "check_base93.vhd"),
                      join("check", "src", "check_special_types93.vhd"),
                      join("run", "src", "run_base93.vhd"),
                      join("run", "src", "run_special_types93.vhd")]

        elif self._vhdl_standard in ('2002', '2008'):
            if mock_log:
                files += [join("logging", "src", "log_base.vhd"),
                          join("logging", "src", "log_special_types200x_mock.vhd"),
                          join("logging", "src", "log_base_api.vhd")]
            else:
                files += [join("logging", "src", "log_base.vhd"),
                          join("logging", "src", "log_special_types200x.vhd"),
                          join("logging", "src", "log_base_api.vhd")]

            files += [join("check", "src", "check_base.vhd"),
                      join("check", "src", "check_special_types200x.vhd"),
                      join("run", "src", "run_base.vhd"),
                      join("run", "src", "run_special_types200x.vhd")]

            if self._vhdl_standard == '2008':
                files += ["vunit_context.vhd"]

        library = self.add_library(library_name)
        for file_name in files:
            library.add_source_files(join(self._builtin_vhdl_path, file_name))

    def add_array_util(self, library_name="vunit_lib"):
        """
        Add array utility package
        """
        if self._vhdl_standard != '2008':
            raise RuntimeError("Array utility only supports vhdl 2008")

        library = self.library(library_name)
        library.add_source_files(join(self._builtin_vhdl_path, "array", "src", "array_pkg.vhd"))

    def add_osvvm(self, library_name="osvvm"):
        if not library_name in self._project._libraries:
            library = self.add_library(library_name)
        else:
            library = self.library(library_name)

        library.add_source_files(join(self._builtin_vhdl_path, "osvvm", "*.vhd"),
                                 preprocessors=[]) # No pre-processing at all
示例#19
0
文件: ui.py 项目: darwinbeing/vunit
class VUnit(object):  # pylint: disable=too-many-instance-attributes, too-many-public-methods
    """
    The public interface of VUnit

    :example:

    .. code-block:: python

       from vunit import VUnit
    """

    @classmethod
    def from_argv(cls, argv=None, compile_builtins=True):
        """
        Create VUnit instance from command line arguments.

        :param argv: Use explicit argv instead of actual command line argument
        :param compile_builtins: Do not compile builtins. Used for VUnit internal testing.
        :returns: A :class:`.VUnit` object instance

        :example:

        .. code-block:: python

           from vunit import VUnit
           prj = VUnit.from_argv()

        """
        args = VUnitCLI().parse_args(argv=argv)
        return cls.from_args(args, compile_builtins=compile_builtins)

    @classmethod
    def from_args(cls, args, compile_builtins=True):
        """
        Create VUnit instance from args namespace.
        Intended for users who adds custom command line options.
        See :class:`vunit.vunit_cli.VUnitCLI` class to learn about
        adding custom command line options.

        :param args: The parsed argument namespace object
        :param compile_builtins: Do not compile builtins. Used for VUnit internal testing.
        :returns: A :class:`.VUnit` object instance
        """
        def test_filter(name):
            return any(fnmatch(name, pattern) for pattern in args.test_patterns)

        return cls(output_path=args.output_path,
                   clean=args.clean,
                   vhdl_standard=select_vhdl_standard(),
                   use_debug_codecs=args.use_debug_codecs,
                   no_color=args.no_color,
                   verbose=args.verbose,
                   xunit_xml=args.xunit_xml,
                   log_level=args.log_level,
                   test_filter=test_filter,
                   list_only=args.list,
                   list_files_only=args.files,
                   compile_only=args.compile,
                   keep_compiling=args.keep_compiling,
                   elaborate_only=args.elaborate,
                   compile_builtins=compile_builtins,
                   simulator_factory=SimulatorFactory(args),
                   num_threads=args.num_threads,
                   exit_0=args.exit_0)

    def __init__(self,  # pylint: disable=too-many-locals, too-many-arguments
                 output_path,
                 simulator_factory,
                 clean=False,
                 use_debug_codecs=False,
                 no_color=False,
                 verbose=False,
                 xunit_xml=None,
                 log_level="warning",
                 test_filter=None,
                 list_only=False,
                 list_files_only=False,
                 compile_only=False,
                 keep_compiling=False,
                 elaborate_only=False,
                 vhdl_standard='2008',
                 compile_builtins=True,
                 num_threads=1,
                 exit_0=False):

        self._configure_logging(log_level)
        self._elaborate_only = elaborate_only
        self._output_path = abspath(output_path)

        if no_color:
            self._printer = NO_COLOR_PRINTER
        else:
            self._printer = COLOR_PRINTER

        self._verbose = verbose
        self._xunit_xml = xunit_xml

        self._test_filter = test_filter if test_filter is not None else lambda name: True
        self._list_only = list_only
        self._list_files_only = list_files_only
        self._compile_only = compile_only
        self._keep_compiling = keep_compiling
        self._vhdl_standard = vhdl_standard

        self._tb_filter = tb_filter
        self._configuration = TestConfiguration()
        self._external_preprocessors = []
        self._location_preprocessor = None
        self._check_preprocessor = None
        self._use_debug_codecs = use_debug_codecs

        self._simulator_factory = simulator_factory
        self._create_output_path(clean)

        self._project = None
        self._create_project()
        self._num_threads = num_threads
        self._exit_0 = exit_0

        if compile_builtins:
            self.add_builtins(library_name="vunit_lib")

    def _create_project(self):
        """
        Create Project instance
        """
        database = self._create_database()
        self._project = Project(
            vhdl_parser=CachedVHDLParser(database=database),
            verilog_parser=VerilogParser(database=database),
            depend_on_package_body=self._simulator_factory.package_users_depend_on_bodies())

    def _create_database(self):
        """
        Create a persistent database to store expensive parse results

        Check for Python version used to create the database is the
        same as the running python instance or re-create
        """
        project_database_file_name = join(self._output_path, "project_database")
        create_new = False
        key = b"version"
        version = str((6, sys.version)).encode()
        database = None
        try:
            database = DataBase(project_database_file_name)
            create_new = (key not in database) or (database[key] != version)
        except KeyboardInterrupt:
            raise
        except:  # pylint: disable=bare-except
            traceback.print_exc()
            create_new = True

        if create_new:
            database = DataBase(project_database_file_name, new=True)
        database[key] = version

        return PickledDataBase(database)

    @staticmethod
    def _configure_logging(log_level):
        """
        Configure logging based on log_level string
        """
        level = getattr(logging, log_level.upper())
        logging.basicConfig(filename=None, format='%(levelname)7s - %(message)s', level=level)

    def add_external_library(self, library_name, path):
        """
        Add an externally compiled library as a black-box

        :param library_name: The name of the external library
        :param path: The path to the external library
        :returns: The created :class:`.Library` object

        :example:

        .. code-block:: python

           prj.add_external_library("unisim", "path/to/unisim/")

        """
        self._project.add_library(library_name, abspath(path), is_external=True)
        return self._create_library_facade(library_name)

    def add_library(self, library_name):
        """
        Add a library managed by VUnit.

        :param library_name: The name of the library
        :returns: The created :class:`.Library` object

        :example:

        .. code-block:: python

           library = prj.add_library("lib")

        """
        path = join(self._simulator_factory.simulator_output_path, "libraries", library_name)
        self._project.add_library(library_name, abspath(path))
        return self._create_library_facade(library_name)

    def library(self, library_name):
        """
        Get a library

        :param library_name: The name of the library
        :returns: A :class:`.Library` object
        """
        if not self._project.has_library(library_name):
            raise KeyError(library_name)
        return self._create_library_facade(library_name)

    def _create_library_facade(self, library_name):
        """
        Create a Library object to be exposed to users
        """
        return Library(library_name, self, self._project, self._configuration)

    def set_generic(self, name, value):
        """
        Globally set a value of generic

        :param name: The name of the generic
        :param value: The value of the generic

        :example:

        .. code-block:: python

           prj.set_generic("data_width", 16)

        """
        self._configuration.set_generic(name.lower(), value, scope=create_scope())

    def set_parameter(self, name, value):
        """
        Globally set value of parameter

        :param name: The name of the parameter
        :param value: The value of the parameter

        :example:

        .. code-block:: python

           prj.set_parameter("data_width", 16)

        """
        self._configuration.set_generic(name, value, scope=create_scope())

    def set_sim_option(self, name, value):
        """
        Globally set simulation option

        :param name: |simulation_options|
        :param value: The value of the simulation option

        :example:

        .. code-block:: python

           prj.set_sim_option("ghdl.flags", ["--no-vital-checks"])

        """
        self._configuration.set_sim_option(name, value, scope=create_scope())

    def set_compile_option(self, name, value):
        """
        Globally set compile option

        :param name: |compile_option|
        :param value: The value of the compile option

        :example:

        .. code-block:: python

           prj.set_compile_option("ghdl.flags", ["--no-vital-checks"])

        """
        for source_file in self._project.get_source_files_in_order():
            source_file.set_compile_option(name, value)

    def add_compile_option(self, name, value):
        """
        Globally add compile option

        :param name: |compile_option|
        :param value: The value of the compile option
        """
        for source_file in self._project.get_source_files_in_order():
            source_file.add_compile_option(name, value)

    def set_pli(self, value):
        """
        Globally Set pli

        :param value: A list of PLI object file names
        """
        self._configuration.set_pli(value, scope=create_scope())

    def disable_ieee_warnings(self):
        """
        Globally disable ieee warnings
        """
        self._configuration.disable_ieee_warnings(scope=create_scope())

    def get_source_file(self, file_name, library_name=None):
        """
        Get a source file

        :param file_name: The name of the file as a relative or absolute path
        :param library_name: The name of a specific library to search if not all libraries
        :returns: A :class:`.SourceFile` object
        """

        files = self.get_source_files(file_name, library_name, allow_empty=True)
        if len(files) > 1:
            raise ValueError("Found file named '%s' in multiple-libraries, "
                             "add explicit library_name." % file_name)
        elif len(files) == 0:
            if library_name is None:
                raise ValueError("Found no file named '%s'" % file_name)
            else:
                raise ValueError("Found no file named '%s' in library '%s'"
                                 % (file_name, library_name))
        return files[0]

    def get_source_files(self, pattern="*", library_name=None, allow_empty=False):
        """
        Get a list of source files

        :param pattern: A wildcard pattern matching either an absolute or relative path
        :param library_name: The name of a specific library to search if not all libraries
        :param allow_empty: To disable an error if no files matched the pattern
        :returns: A :class:`.SourceFileList` object
        """
        results = []
        for source_file in self._project.get_source_files_in_order():
            if library_name is not None:
                if source_file.library.name != library_name:
                    continue

            if not (fnmatch(abspath(source_file.name), pattern) or
                    fnmatch(ostools.simplify_path(source_file.name), pattern)):
                continue

            results.append(SourceFile(source_file, self._project, self))

        if (not allow_empty) and len(results) == 0:
            raise ValueError(("Pattern %r did not match any file. "
                              "Use allow_empty=True to avoid exception,") % pattern)

        return SourceFileList(results)

    def add_source_files(self,   # pylint: disable=too-many-arguments
                         files, library_name, preprocessors=None, include_dirs=None, defines=None, allow_empty=False):
        """
        Add source files matching wildcard pattern to library

        :param files: A wildcard pattern matching the files to add or a list of files
        :param library_name: The name of the library to add files into
        :param include_dirs: A list of include directories
        :param defines: A dictionary containing Verilog defines to be set
        :param allow_empty: To disable an error if no files matched the pattern
        :returns: A list of files (:class:`.SourceFileList`) which were added

        :example:

        .. code-block:: python

           prj.add_source_files("*.vhd", "lib")

        """
        if _is_iterable_not_string(files):
            files = [files]

        file_names = []
        for pattern in files:
            new_file_names = glob(pattern)

            if (not allow_empty) and len(new_file_names) == 0:
                raise ValueError(("Pattern %r did not match any file. "
                                  "Use allow_empty=True to avoid exception,") % pattern)
            file_names += new_file_names

        return SourceFileList(source_files=[
            self.add_source_file(file_name, library_name, preprocessors, include_dirs, defines)
            for file_name in file_names])

    def add_source_file(self, file_name, library_name, preprocessors=None, include_dirs=None, defines=None):
        """
        Add source file to library

        :param file_name: The name of the file
        :param library_name: The name of the library to add the file into
        :param include_dirs: A list of include directories
        :param defines: A dictionary containing Verilog defines to be set
        :returns: The :class:`.SourceFile` which was added

        :example:

        .. code-block:: python

           prj.add_source_file("file.vhd", "lib")

        """
        file_type = file_type_of(file_name)

        if file_type == "verilog":
            include_dirs = include_dirs if include_dirs is not None else []
            include_dirs = add_verilog_include_dir(include_dirs)

        file_name = self._preprocess(library_name, abspath(file_name), preprocessors)
        return SourceFile(self._project.add_source_file(file_name,
                                                        library_name,
                                                        file_type=file_type,
                                                        include_dirs=include_dirs,
                                                        defines=defines),
                          self._project,
                          self)

    def _preprocess(self, library_name, file_name, preprocessors):
        """
        Preprocess file_name within library_name using explicit preprocessors
        if preprocessors is None then use implicit globally defined processors
        """
        # @TODO dependency checking etc...

        if preprocessors is None:
            preprocessors = [self._location_preprocessor, self._check_preprocessor]
            preprocessors = [p for p in preprocessors if p is not None]
            preprocessors = self._external_preprocessors + preprocessors

        if len(preprocessors) == 0:
            return file_name

        code = ostools.read_file(file_name)
        for preprocessor in preprocessors:
            code = preprocessor.run(code, basename(file_name))

        pp_file_name = join(self._preprocessed_path, library_name, basename(file_name))

        idx = 1
        while ostools.file_exists(pp_file_name):
            LOGGER.debug("Preprocessed file exists '%s', adding prefix", pp_file_name)
            pp_file_name = join(self._preprocessed_path,
                                library_name, "%i_%s" % (idx, basename(file_name)))
            idx += 1

        ostools.write_file(pp_file_name, code)
        return pp_file_name

    def add_preprocessor(self, preprocessor):
        """
        Add a custom preprocessor to be used on all files, must be called before adding any files
        """
        self._external_preprocessors.append(preprocessor)

    def enable_location_preprocessing(self, additional_subprograms=None):
        """
        Enable location preprocessing, must be called before adding any files
        """
        preprocessor = LocationPreprocessor()
        if additional_subprograms is not None:
            for subprogram in additional_subprograms:
                preprocessor.add_subprogram(subprogram)
        self._location_preprocessor = preprocessor

    def enable_check_preprocessing(self):
        """
        Enable check preprocessing, must be called before adding any files
        """
        self._check_preprocessor = CheckPreprocessor()

    def main(self):
        """
        Run vunit main function and exit
        """
        try:
            all_ok = self._main()
        except KeyboardInterrupt:
            exit(1)
        except CompileError:
            exit(1)
        except TestScannerError:
            exit(1)
        except SystemExit:
            exit(1)
        except:  # pylint: disable=bare-except
            traceback.print_exc()
            exit(1)

        if (not all_ok) and (not self._exit_0):
            exit(1)

        exit(0)

    def _main(self):
        """
        Base vunit main function without performing exit
        """
        if self._list_only:
            return self._main_list_only()

        if self._list_files_only:
            return self._main_list_files_only()

        if self._compile_only:
            return self._main_compile_only()

        simulator_if = self._create_simulator_if()
        test_cases = self._create_tests(simulator_if)

        self._compile(simulator_if)

        start_time = ostools.get_time()
        report = TestReport(printer=self._printer)
        try:
            self._run_test(test_cases, report)
            simulator_if.post_process(self._simulator_factory.simulator_output_path)
        except KeyboardInterrupt:
            print()
            LOGGER.debug("_main: Caught Ctrl-C shutting down")
        finally:
            del test_cases
            del simulator_if

        report.set_real_total_time(ostools.get_time() - start_time)
        self._post_process(report)

        return report.all_ok()

    def _main_list_only(self):
        """
        Main function when only listing test cases
        """
        simulator_if = None
        test_suites = self._create_tests(simulator_if)

        for test_suite in test_suites:
            for name in test_suite.test_cases:
                print(name)
        print("Listed %i tests" % test_suites.num_tests())
        return True

    def _main_list_files_only(self):
        """
        Main function when only listing files
        """
        files = self.get_compile_order()
        for source_file in files:
            print("%s, %s" % (source_file.library.name, source_file.name))
        print("Listed %i files" % len(files))
        return True

    def _main_compile_only(self):
        """
        Main function when only compiling
        """
        simulator_if = self._create_simulator_if()
        self._compile(simulator_if)
        return True

    def _create_output_path(self, clean):
        """
        Create or re-create the output path if necessary
        """
        if clean:
            ostools.renew_path(self._output_path)
        elif not exists(self._output_path):
            os.makedirs(self._output_path)

        ostools.renew_path(self._preprocessed_path)

    def _create_simulator_if(self):
        """
        Create a simulator interface instance
        """
        return self._simulator_factory.create()

    @property
    def vhdl_standard(self):
        return self._vhdl_standard

    @property
    def _preprocessed_path(self):
        return join(self._output_path, "preprocessed")

    @property
    def codecs_path(self):
        return join(self._output_path, "codecs")

    @property
    def use_debug_codecs(self):
        return self._use_debug_codecs

    def _create_tests(self, simulator_if):
        """
        Create the test suites by scanning the project
        """
        scanner = TestScanner(simulator_if,
                              self._configuration,
                              elaborate_only=self._elaborate_only)
        test_list = scanner.from_project(self._project, entity_filter=self._tb_filter)

        if test_list.num_tests() == 0:
            LOGGER.warning("Test scanner found no test benches using current filter rule:\n%s",
                           self._tb_filter.__doc__)

        test_list.keep_matches(self._test_filter)
        return test_list

    def _compile(self, simulator_if):
        """
        Compile entire project
        """
        simulator_if.compile_project(self._project, self._vhdl_standard,
                                     continue_on_error=self._keep_compiling)

    def _run_test(self, test_cases, report):
        """
        Run the test suites and return the report
        """
        runner = TestRunner(report,
                            join(self._output_path, "tests"),
                            verbose=self._verbose,
                            num_threads=self._num_threads)
        runner.run(test_cases)

    def _post_process(self, report):
        """
        Print the report to stdout and optionally write it to an XML file
        """
        report.print_str()

        if self._xunit_xml is not None:
            xml = report.to_junit_xml_str()
            ostools.write_file(self._xunit_xml, xml)

    def add_builtins(self, library_name="vunit_lib", mock_lang=False, mock_log=False):
        """
        Add vunit VHDL builtin libraries
        """
        library = self.add_library(library_name)
        supports_context = self._simulator_factory.supports_vhdl_2008_contexts()
        add_vhdl_builtins(library, self._vhdl_standard, mock_lang, mock_log,
                          supports_context=supports_context)

    def add_com(self, library_name="vunit_lib", use_debug_codecs=None):
        """
        Add communication package

        :param use_debug_codecs: Use human readable debug codecs

           `None`: Use command line argument setting

           `False`: Never use debug codecs

           `True`: Always use debug codecs
        """
        if not self._project.has_library(library_name):
            library = self.add_library(library_name)
        else:
            library = self.library(library_name)

        if use_debug_codecs is not None:
            self._use_debug_codecs = use_debug_codecs

        supports_context = self._simulator_factory.supports_vhdl_2008_contexts()

        add_com(library, self._vhdl_standard,
                use_debug_codecs=self._use_debug_codecs,
                supports_context=supports_context)

    def add_array_util(self, library_name="vunit_lib"):
        """
        Add array utility package
        """
        library = self.library(library_name)
        add_array_util(library, self._vhdl_standard)

    def add_osvvm(self, library_name="osvvm"):
        """
        Add osvvm library
        """
        if not self._project.has_library(library_name):
            library = self.add_library(library_name)
        else:
            library = self.library(library_name)
        add_osvvm(library)

    def get_compile_order(self, source_files=None):
        """
        Get the compile order of all or specific source files and
        their dependencies

        :param source_files: A list of :class:`.SourceFile` objects or `None` meaing all
        :returns: A list of :class:`.SourceFile` objects in compile order.
        """
        if source_files is None:
            source_files = self.get_source_files()

        target_files = [source_file._source_file  # pylint: disable=protected-access
                        for source_file in source_files]
        source_files = self._project.get_dependencies_in_compile_order(target_files)
        return SourceFileList([SourceFile(source_file, self._project, self)
                               for source_file in source_files])
示例#20
0
class VUnit:
    """
    The public interface of VUnit
    """

    _builtin_vhdl_path = abspath(join(dirname(__file__), "..", "vhdl"))

    @classmethod
    def from_argv(cls, argv=None):
        """
        Create VUnit instance from command line arguments
        Can take arguments from 'argv' if not None  instead of sys.argv
        """
        parser = cls._create_argument_parser()
        args = parser.parse_args(args=argv)

        def test_filter(name):
            return any(
                fnmatch(name, pattern) for pattern in args.test_patterns)

        return cls(output_path=args.output_path,
                   clean=args.clean,
                   no_color=args.no_color,
                   verbose=args.verbose,
                   xunit_xml=args.xunit_xml,
                   log_level=args.log_level,
                   test_filter=test_filter,
                   list_only=args.list,
                   compile_only=args.compile,
                   gui=args.gui)

    @classmethod
    def _create_argument_parser(cls):
        parser = argparse.ArgumentParser(
            description='VUnit command line tool.')

        parser.add_argument('test_patterns',
                            metavar='tests',
                            nargs='*',
                            default='*',
                            help='Tests to run')

        parser.add_argument('-l',
                            '--list',
                            action='store_true',
                            default=False,
                            help='Only list all test cases')

        parser.add_argument('--compile',
                            action='store_true',
                            default=False,
                            help='Only compile project')

        parser.add_argument('--clean',
                            action='store_true',
                            default=False,
                            help='Remove output path first')

        parser.add_argument(
            '-o',
            '--output-path',
            default=join(abspath(getcwd()), "vunit_out"),
            help='Output path for compilation and simulation artifacts')

        parser.add_argument('-x',
                            '--xunit-xml',
                            default=None,
                            help='Xunit test report .xml file')

        parser.add_argument(
            '-v',
            '--verbose',
            action="store_true",
            default=False,
            help='Print test output immediately and not only when failure')

        parser.add_argument('--no-color',
                            action='store_true',
                            default=False,
                            help='Do not color output')

        parser.add_argument('--gui',
                            action='store_true',
                            default=False,
                            help='Open test case(s) in simulator gui')

        parser.add_argument('--log-level',
                            default="warning",
                            choices=["info", "error", "warning", "debug"])

        return parser

    def __init__(self,
                 output_path,
                 clean=False,
                 no_color=False,
                 verbose=False,
                 xunit_xml=None,
                 log_level="warning",
                 test_filter=None,
                 list_only=False,
                 compile_only=False,
                 elaborate_only=False,
                 vhdl_standard='2008',
                 compile_builtins=True,
                 persistent_sim=True,
                 gui=False):

        self._project = Project()

        self._output_path = output_path
        self._clean = clean

        if no_color:
            self._printer = NoColorPrinter
        else:
            self._printer = ColorPrinter

        self._verbose = verbose
        self._xunit_xml = xunit_xml

        level = getattr(logging, log_level.upper())
        logging.basicConfig(filename=None,
                            format='%(levelname)7s - %(message)s',
                            level=level)

        self._test_filter = test_filter if test_filter is not None else lambda name: True
        self._list_only = list_only
        self._compile_only = compile_only
        self._elaborate_only = elaborate_only
        self._vhdl_standard = vhdl_standard

        self._tb_filter = tb_filter
        self._persistent_sim = persistent_sim
        self._gui = gui
        self._configuration = TestConfiguration()
        self._external_preprocessors = []
        self._location_preprocessor = None
        self._check_preprocessor = None

        self._create_output_path()

        if compile_builtins:
            self.add_builtins(library_name="vunit_lib")

    def add_external_library(self, library_name, path):
        """
        Add external black box library
        """
        self._project.add_library(library_name,
                                  abspath(path),
                                  is_external=True)
        return LibraryFacade(library_name, self)

    def add_library(self, library_name):
        """
        Add vunit managed white box library
        """
        path = join(self._output_path, "libraries", library_name)
        self._project.add_library(library_name, abspath(path))
        return LibraryFacade(library_name, self)

    def library(self, library_name):
        """
        Get reference to library
        """
        if not library_name in self._project._libraries:
            raise KeyError(library_name)
        return LibraryFacade(library_name, self)

    def set_generic(self, name, value):
        " Globally set generic "
        self._configuration.set_generic(name, value, scope="")

    def set_pli(self, value):
        " Globally set pli "
        self._configuration.set_generic(value, scope="")

    def add_source_files(self, pattern, library_name, preprocessors=None):
        """
        Add source files matching wildcard pattern to library
        """

        for file_name in glob(pattern):
            file_name = self._preprocess(library_name, abspath(file_name),
                                         preprocessors)
            self._project.add_source_file(file_name,
                                          library_name,
                                          file_type=file_type_of(file_name))

    def _preprocess(self, library_name, file_name, preprocessors):
        # @TODO dependency checking etc...

        if preprocessors is None:
            preprocessors = [
                self._location_preprocessor, self._check_preprocessor
            ]
            preprocessors = [p for p in preprocessors if not p is None]
            preprocessors = self._external_preprocessors + preprocessors

        if len(preprocessors) == 0:
            return file_name

        code = ostools.read_file(file_name)
        for p in preprocessors:
            code = p.run(code, basename(file_name))

        pp_file_name = join(self._preprocessed_path, library_name,
                            basename(file_name))

        idx = 1
        while ostools.file_exists(pp_file_name):
            logger.debug("Preprocessed file exists '%s', adding prefix" %
                         pp_file_name)
            pp_file_name = join(self._preprocessed_path, library_name,
                                "%i_%s" % (idx, basename(file_name)))
            idx += 1

        ostools.write_file(pp_file_name, code)
        return pp_file_name

    def add_preprocessor(self, preprocessor):
        """
        Add a custom preprocessor to be used on all files, must be called before adding any files
        """
        self._external_preprocessors.append(preprocessor)

    def enable_location_preprocessing(self, additional_subprograms=None):
        """
        Enable location preprocessing, must be called before adding any files
        """
        p = LocationPreprocessor()
        if not additional_subprograms is None:
            for subprogram in additional_subprograms:
                p.add_subprogram(subprogram)
        self._location_preprocessor = p

    def enable_check_preprocessing(self):
        """
        Enable check preprocessing, must be called before adding any files
        """
        self._check_preprocessor = CheckPreprocessor()

    def main(self):
        """
        Run vunit main function and exit with code
        """
        try:
            all_ok = self._main()
        except KeyboardInterrupt:
            # Ctrl-C
            exit(1)
        except CompileError:
            exit(1)
        except TestScannerError:
            exit(1)
        except:
            traceback.print_exc()
            exit(1)

        if not all_ok:
            exit(1)

        exit(0)

    def _main(self):
        if self._list_only:
            return self._main_list_only()

        if self._compile_only:
            return self._main_compile_only()

        simulator_if = self._create_simulator_if()
        test_cases = self._create_tests(simulator_if)
        self._compile(simulator_if)

        report = self._run_test(test_cases)
        del simulator_if
        self._post_process(report)
        return report.all_ok()

    def _main_list_only(self):
        simulator_if = None
        test_suites = self._create_tests(simulator_if)
        num_tests = 0
        for test_suite in test_suites:
            for name in test_suite.test_cases:
                print(name)
                num_tests += 1
        print("Listed %i tests" % num_tests)
        return True

    def _main_compile_only(self):
        simulator_if = self._create_simulator_if()
        self._compile(simulator_if)
        return True

    def _create_output_path(self):
        if self._clean and exists(self._output_path):
            rmtree(self._output_path)

        if exists(self._preprocessed_path):
            rmtree(self._preprocessed_path)

        if not exists(self._output_path):
            makedirs(self._output_path)

    def _create_simulator_if(self):
        return ModelSimInterface(join(self._output_path, "modelsim.ini"),
                                 persistent=self._persistent_sim
                                 and not self._gui,
                                 gui=self._gui)

    @property
    def _preprocessed_path(self):
        return join(self._output_path, "preprocessed")

    def _create_tests(self, simulator_if):
        scanner = TestScanner(simulator_if,
                              self._configuration,
                              elaborate_only=self._elaborate_only)
        test_list = scanner.from_project(self._project,
                                         entity_filter=self._tb_filter)
        test_list.keep_matches(self._test_filter)
        return test_list

    def _compile(self, simulator_if):
        simulator_if.compile_project(self._project, self._vhdl_standard)

    def _run_test(self, test_cases):
        report = TestReport(printer=self._printer)
        runner = TestRunner(report,
                            join(self._output_path, "tests"),
                            verbose=self._verbose)
        runner.run(test_cases)
        return report

    def _post_process(self, report):
        report.print_str()

        if not self._xunit_xml is None:
            xml = report.to_junit_xml_str()
            ostools.write_file(self._xunit_xml, xml)

    def add_builtins(self, library_name, mock_lang=False, mock_log=False):
        files = []

        if mock_lang:
            files += [join("vhdl", "src", "lang", "lang_mock.vhd")]
        else:
            files += [join("vhdl", "src", "lang", "lang.vhd")]

        files += [
            join("vhdl", "src", "lib", "std", "textio.vhd"),
            join("string_ops", "src", "string_ops.vhd"),
            join("check", "src", "check.vhd"),
            join("check", "src", "check_api.vhd"),
            join("check", "src", "check_base_api.vhd"),
            join("check", "src", "check_types.vhd"),
            join("run", "src", "run.vhd"),
            join("run", "src", "run_api.vhd"),
            join("run", "src", "run_types.vhd"),
            join("run", "src", "run_base_api.vhd")
        ]

        files += [
            join("logging", "src", "log_api.vhd"),
            join("logging", "src", "log_formatting.vhd"),
            join("logging", "src", "log.vhd"),
            join("logging", "src", "log_types.vhd")
        ]

        files += [join("dictionary", "src", "dictionary.vhd")]

        files += [join("path", "src", "path.vhd")]

        if self._vhdl_standard == '93':
            if mock_log:
                files += [
                    join("logging", "src", "log_base93_mock.vhd"),
                    join("logging", "src", "log_special_types93.vhd"),
                    join("logging", "src", "log_base_api_mock.vhd")
                ]
            else:
                files += [
                    join("logging", "src", "log_base93.vhd"),
                    join("logging", "src", "log_special_types93.vhd"),
                    join("logging", "src", "log_base_api.vhd")
                ]

            files += [
                join("check", "src", "check_base93.vhd"),
                join("check", "src", "check_special_types93.vhd"),
                join("run", "src", "run_base93.vhd"),
                join("run", "src", "run_special_types93.vhd")
            ]

        elif self._vhdl_standard in ('2002', '2008'):
            if mock_log:
                files += [
                    join("logging", "src", "log_base.vhd"),
                    join("logging", "src", "log_special_types200x_mock.vhd"),
                    join("logging", "src", "log_base_api.vhd")
                ]
            else:
                files += [
                    join("logging", "src", "log_base.vhd"),
                    join("logging", "src", "log_special_types200x.vhd"),
                    join("logging", "src", "log_base_api.vhd")
                ]

            files += [
                join("check", "src", "check_base.vhd"),
                join("check", "src", "check_special_types200x.vhd"),
                join("run", "src", "run_base.vhd"),
                join("run", "src", "run_special_types200x.vhd")
            ]

            if self._vhdl_standard == '2008':
                files += ["vunit_context.vhd"]

        library = self.add_library(library_name)
        for file_name in files:
            library.add_source_files(join(self._builtin_vhdl_path, file_name))

    def add_array_util(self, library_name="vunit_lib"):
        """
        Add array utility package
        """
        if self._vhdl_standard != '2008':
            raise RuntimeError("Array utility only supports vhdl 2008")

        library = self.library(library_name)
        library.add_source_files(
            join(self._builtin_vhdl_path, "array", "src", "array_pkg.vhd"))

    def add_osvvm(self, library_name="osvvm"):
        if not library_name in self._project._libraries:
            library = self.add_library(library_name)
        else:
            library = self.library(library_name)

        library.add_source_files(join(self._builtin_vhdl_path, "osvvm",
                                      "*.vhd"),
                                 preprocessors=[])  # No pre-processing at all
示例#21
0
文件: ui.py 项目: varunnagpaal/vunit
class VUnit(object):  # pylint: disable=too-many-instance-attributes, too-many-public-methods
    """
    The public interface of VUnit
    """

    @classmethod
    def from_argv(cls, argv=None, compile_builtins=True):
        """
        Create VUnit instance from command line arguments
        Can take arguments from 'argv' if not None  instead of sys.argv
        """
        args = VUnitCLI().parse_args(argv=argv)
        return cls.from_args(args, compile_builtins=compile_builtins)

    @classmethod
    def from_args(cls, args, compile_builtins=True):
        """
        Create VUnit instance from args namespace
        """
        def test_filter(name):
            return any(fnmatch(name, pattern) for pattern in args.test_patterns)

        return cls(output_path=args.output_path,
                   clean=args.clean,
                   vhdl_standard=select_vhdl_standard(),
                   use_debug_codecs=args.use_debug_codecs,
                   no_color=args.no_color,
                   verbose=args.verbose,
                   xunit_xml=args.xunit_xml,
                   log_level=args.log_level,
                   test_filter=test_filter,
                   list_only=args.list,
                   compile_only=args.compile,
                   elaborate_only=args.elaborate,
                   compile_builtins=compile_builtins,
                   simulator_factory=SimulatorFactory(args),
                   num_threads=args.num_threads,
                   exit_0=args.exit_0)

    def __init__(self,  # pylint: disable=too-many-locals, too-many-arguments
                 output_path,
                 simulator_factory,
                 clean=False,
                 use_debug_codecs=False,
                 no_color=False,
                 verbose=False,
                 xunit_xml=None,
                 log_level="warning",
                 test_filter=None,
                 list_only=False,
                 compile_only=False,
                 elaborate_only=False,
                 vhdl_standard='2008',
                 compile_builtins=True,
                 num_threads=1,
                 exit_0=False):

        self._configure_logging(log_level)

        self._output_path = output_path

        if no_color:
            self._printer = NO_COLOR_PRINTER
        else:
            self._printer = COLOR_PRINTER

        self._verbose = verbose
        self._xunit_xml = xunit_xml

        self._test_filter = test_filter if test_filter is not None else lambda name: True
        self._list_only = list_only
        self._compile_only = compile_only
        self._vhdl_standard = vhdl_standard

        self._tb_filter = tb_filter
        self._configuration = TestConfiguration(elaborate_only=elaborate_only)
        self._external_preprocessors = []
        self._location_preprocessor = None
        self._check_preprocessor = None
        self._use_debug_codecs = use_debug_codecs

        self._simulator_factory = simulator_factory
        self._create_output_path(clean)

        self._project = None
        self._create_project()
        self._num_threads = num_threads
        self._exit_0 = exit_0

        if compile_builtins:
            self.add_builtins(library_name="vunit_lib")

    def _create_project(self):
        """
        Create Project instance
        """
        database = self._create_database()
        self._project = Project(
            vhdl_parser=CachedVHDLParser(database=database),
            depend_on_package_body=self._simulator_factory.package_users_depend_on_bodies())

    def _create_database(self):
        """
        Create a persistent database to store expensive parse results

        Check for Python version used to create the database is the
        same as the running python instance or re-create
        """
        project_database_file_name = join(self._output_path, "project_database")
        create_new = False
        key = b"version"
        version = str((4, sys.version)).encode()
        database = None
        try:
            database = DataBase(project_database_file_name)
            create_new = (key not in database) or (database[key] != version)
        except KeyboardInterrupt:
            raise
        except:  # pylint: disable=bare-except
            traceback.print_exc()
            create_new = True

        if create_new:
            database = DataBase(project_database_file_name, new=True)
        database[key] = version

        return PickledDataBase(database)

    @staticmethod
    def _configure_logging(log_level):
        """
        Configure logging based on log_level string
        """
        level = getattr(logging, log_level.upper())
        logging.basicConfig(filename=None, format='%(levelname)7s - %(message)s', level=level)

    def add_external_library(self, library_name, path):
        """
        Add external black box library
        """
        self._project.add_library(library_name, abspath(path), is_external=True)
        return self._create_library_facade(library_name)

    def add_library(self, library_name):
        """
        Add vunit managed white box library
        """
        path = join(self._simulator_factory.simulator_output_path, "libraries", library_name)
        self._project.add_library(library_name, abspath(path))
        return self._create_library_facade(library_name)

    def library(self, library_name):
        """
        Get reference to library
        """
        if not self._project.has_library(library_name):
            raise KeyError(library_name)
        return self._create_library_facade(library_name)

    def _create_library_facade(self, library_name):
        """
        Create a Library object to be exposed to users
        """
        return LibraryFacade(library_name, self, self._project, self._configuration)

    def set_generic(self, name, value):
        """
        Globally set generic
        """
        self._configuration.set_generic(name.lower(), value, scope=create_scope())

    def set_parameter(self, name, value):
        """
        Globally set parameter
        """
        self.set_generic(name, value)

    def set_sim_option(self, name, value):
        """
        Globally set simulation option
        """
        self._configuration.set_sim_option(name, value, scope=create_scope())

    def set_pli(self, value):
        """
        Globally set pli
        """
        self._configuration.set_pli(value, scope=create_scope())

    def disable_ieee_warnings(self):
        """
        Globally disable ieee warnings
        """
        self._configuration.disable_ieee_warnings(scope=create_scope())

    def add_source_files(self, pattern, library_name, preprocessors=None, include_dirs=None):
        """
        Add source files matching wildcard pattern to library
        """
        for file_name in glob(pattern):
            self.add_source_file(file_name, library_name, preprocessors, include_dirs)

    def add_source_file(self, file_name, library_name, preprocessors=None, include_dirs=None):
        """
        Add source file to library
        """
        file_type = file_type_of(file_name)

        if file_type == "verilog":
            include_dirs = include_dirs if include_dirs is not None else []
            add_verilog_include_dir(include_dirs)

        file_name = self._preprocess(library_name, abspath(file_name), preprocessors)
        self._project.add_source_file(file_name,
                                      library_name,
                                      file_type=file_type,
                                      include_dirs=include_dirs)

    def _preprocess(self, library_name, file_name, preprocessors):
        """
        Preprocess file_name within library_name using explicit preprocessors
        if preprocessors is None then use implicit globally defined processors
        """
        # @TODO dependency checking etc...

        if preprocessors is None:
            preprocessors = [self._location_preprocessor, self._check_preprocessor]
            preprocessors = [p for p in preprocessors if p is not None]
            preprocessors = self._external_preprocessors + preprocessors

        if len(preprocessors) == 0:
            return file_name

        code = ostools.read_file(file_name)
        for preprocessor in preprocessors:
            code = preprocessor.run(code, basename(file_name))

        pp_file_name = join(self._preprocessed_path, library_name, basename(file_name))

        idx = 1
        while ostools.file_exists(pp_file_name):
            LOGGER.debug("Preprocessed file exists '%s', adding prefix", pp_file_name)
            pp_file_name = join(self._preprocessed_path,
                                library_name, "%i_%s" % (idx, basename(file_name)))
            idx += 1

        ostools.write_file(pp_file_name, code)
        return pp_file_name

    def add_preprocessor(self, preprocessor):
        """
        Add a custom preprocessor to be used on all files, must be called before adding any files
        """
        self._external_preprocessors.append(preprocessor)

    def enable_location_preprocessing(self, additional_subprograms=None):
        """
        Enable location preprocessing, must be called before adding any files
        """
        preprocessor = LocationPreprocessor()
        if additional_subprograms is not None:
            for subprogram in additional_subprograms:
                preprocessor.add_subprogram(subprogram)
        self._location_preprocessor = preprocessor

    def enable_check_preprocessing(self):
        """
        Enable check preprocessing, must be called before adding any files
        """
        self._check_preprocessor = CheckPreprocessor()

    def main(self):
        """
        Run vunit main function and exit with code
        """
        try:
            all_ok = self._main()
        except KeyboardInterrupt:
            exit(1)
        except CompileError:
            exit(1)
        except TestScannerError:
            exit(1)
        except:  # pylint: disable=bare-except
            traceback.print_exc()
            exit(1)

        if (not all_ok) and (not self._exit_0):
            exit(1)

        exit(0)

    def _main(self):
        """
        Base vunit main function without performing exit
        """
        if self._list_only:
            return self._main_list_only()

        if self._compile_only:
            return self._main_compile_only()

        simulator_if = self._create_simulator_if()
        test_cases = self._create_tests(simulator_if)

        self._compile(simulator_if)

        start_time = ostools.get_time()
        report = TestReport(printer=self._printer)
        try:
            self._run_test(test_cases, report)
            simulator_if.post_process(self._simulator_factory.simulator_output_path)
        except KeyboardInterrupt:
            print()
            LOGGER.debug("_main: Caught Ctrl-C shutting down")
        finally:
            del test_cases
            del simulator_if

        report.set_real_total_time(ostools.get_time() - start_time)
        self._post_process(report)

        return report.all_ok()

    def _main_list_only(self):
        """
        Main function when only listing test cases
        """
        simulator_if = None
        test_suites = self._create_tests(simulator_if)
        num_tests = 0
        for test_suite in test_suites:
            for name in test_suite.test_cases:
                print(name)
                num_tests += 1
        print("Listed %i tests" % num_tests)
        return True

    def _main_compile_only(self):
        """
        Main function when only compiling
        """
        simulator_if = self._create_simulator_if()
        self._compile(simulator_if)
        return True

    def _create_output_path(self, clean):
        """
        Create or re-create the output path if necessary
        """
        if clean:
            ostools.renew_path(self._output_path)
        elif not exists(self._output_path):
            os.makedirs(self._output_path)

        ostools.renew_path(self._preprocessed_path)

    def _create_simulator_if(self):
        """
        Create a simulator interface instance
        """
        return self._simulator_factory.create()

    @property
    def vhdl_standard(self):
        return self._vhdl_standard

    @property
    def _preprocessed_path(self):
        return join(self._output_path, "preprocessed")

    @property
    def codecs_path(self):
        return join(self._output_path, "codecs")

    @property
    def use_debug_codecs(self):
        return self._use_debug_codecs

    def _create_tests(self, simulator_if):
        """
        Create the test suites by scanning the project
        """
        scanner = TestScanner(simulator_if,
                              self._configuration)
        test_list = scanner.from_project(self._project, entity_filter=self._tb_filter)
        test_list.keep_matches(self._test_filter)
        return test_list

    def _compile(self, simulator_if):
        """
        Compile entire project
        """
        simulator_if.compile_project(self._project, self._vhdl_standard)

    def _run_test(self, test_cases, report):
        """
        Run the test suites and return the report
        """
        runner = TestRunner(report,
                            join(self._output_path, "tests"),
                            verbose=self._verbose,
                            num_threads=self._num_threads)
        runner.run(test_cases)

    def _post_process(self, report):
        """
        Print the report to stdout and optionally write it to an XML file
        """
        report.print_str()

        if self._xunit_xml is not None:
            xml = report.to_junit_xml_str()
            ostools.write_file(self._xunit_xml, xml)

    def add_builtins(self, library_name="vunit_lib", mock_lang=False, mock_log=False):
        """
        Add vunit VHDL builtin libraries
        """
        library = self.add_library(library_name)
        add_vhdl_builtins(library, self._vhdl_standard, mock_lang, mock_log)

    def add_com(self, library_name="vunit_lib", use_debug_codecs=None):
        """
        Add communication package
        """
        if not self._project.has_library(library_name):
            library = self.add_library(library_name)
        else:
            library = self.library(library_name)
        if use_debug_codecs is not None:
            self._use_debug_codecs = use_debug_codecs
        add_com(library, self._vhdl_standard,
                use_debug_codecs=self._use_debug_codecs)

    def add_array_util(self, library_name="vunit_lib"):
        """
        Add array utility package
        """
        library = self.library(library_name)
        add_array_util(library, self._vhdl_standard)

    def add_osvvm(self, library_name="osvvm"):
        """
        Add osvvm library
        """
        if not self._project.has_library(library_name):
            library = self.add_library(library_name)
        else:
            library = self.library(library_name)
        add_osvvm(library)

    def get_project_compile_order(self, target=None):
        """
        Get all project files in compile order.  An optional target
        file may be specified causing only its direct and indirect
        dependencies to be included.
        """
        if target is not None:
            target = abspath(target)
        return self._project.get_dependencies_in_compile_order(target=target)
示例#22
0
class VUnit(object):  # pylint: disable=too-many-instance-attributes, too-many-public-methods
    """
    The public interface of VUnit

    :example:

    .. code-block:: python

       from vunit import VUnit
    """

    @classmethod
    def from_argv(cls, argv=None, compile_builtins=True):
        """
        Create VUnit instance from command line arguments.

        :param argv: Use explicit argv instead of actual command line argument
        :param compile_builtins: Do not compile builtins. Used for VUnit internal testing.
        :returns: A :class:`.VUnit` object instance

        :example:

        .. code-block:: python

           from vunit import VUnit
           prj = VUnit.from_argv()

        """
        args = VUnitCLI().parse_args(argv=argv)
        return cls.from_args(args, compile_builtins=compile_builtins)

    @classmethod
    def from_args(cls, args, compile_builtins=True):
        """
        Create VUnit instance from args namespace.
        Intended for users who adds custom command line options.
        See :class:`vunit.vunit_cli.VUnitCLI` class to learn about
        adding custom command line options.

        :param args: The parsed argument namespace object
        :param compile_builtins: Do not compile builtins. Used for VUnit internal testing.
        :returns: A :class:`.VUnit` object instance
        """
        def test_filter(name):
            return any(fnmatch(name, pattern) for pattern in args.test_patterns)

        return cls(output_path=args.output_path,
                   clean=args.clean,
                   vhdl_standard=select_vhdl_standard(),
                   use_debug_codecs=args.use_debug_codecs,
                   no_color=args.no_color,
                   verbose=args.verbose,
                   xunit_xml=args.xunit_xml,
                   log_level=args.log_level,
                   test_filter=test_filter,
                   list_only=args.list,
                   list_files_only=args.files,
                   compile_only=args.compile,
                   keep_compiling=args.keep_compiling,
                   elaborate_only=args.elaborate,
                   compile_builtins=compile_builtins,
                   simulator_factory=SimulatorFactory(args),
                   num_threads=args.num_threads,
                   exit_0=args.exit_0)

    def __init__(self,  # pylint: disable=too-many-locals, too-many-arguments
                 output_path,
                 simulator_factory,
                 clean=False,
                 use_debug_codecs=False,
                 no_color=False,
                 verbose=False,
                 xunit_xml=None,
                 log_level="warning",
                 test_filter=None,
                 list_only=False,
                 list_files_only=False,
                 compile_only=False,
                 keep_compiling=False,
                 elaborate_only=False,
                 vhdl_standard='2008',
                 compile_builtins=True,
                 num_threads=1,
                 exit_0=False):

        self._configure_logging(log_level)
        self._elaborate_only = elaborate_only
        self._output_path = abspath(output_path)

        if no_color:
            self._printer = NO_COLOR_PRINTER
        else:
            self._printer = COLOR_PRINTER

        self._verbose = verbose
        self._xunit_xml = xunit_xml

        self._test_filter = test_filter if test_filter is not None else lambda name: True
        self._list_only = list_only
        self._list_files_only = list_files_only
        self._compile_only = compile_only
        self._keep_compiling = keep_compiling
        self._vhdl_standard = vhdl_standard

        self._tb_filter = tb_filter
        self._configuration = TestConfiguration()
        self._external_preprocessors = []
        self._location_preprocessor = None
        self._check_preprocessor = None
        self._use_debug_codecs = use_debug_codecs

        self._simulator_factory = simulator_factory
        self._create_output_path(clean)

        self._project = None
        self._create_project()
        self._num_threads = num_threads
        self._exit_0 = exit_0

        if compile_builtins:
            self.add_builtins(library_name="vunit_lib")

    def _create_project(self):
        """
        Create Project instance
        """
        database = self._create_database()
        self._project = Project(
            vhdl_parser=CachedVHDLParser(database=database),
            verilog_parser=VerilogParser(database=database),
            depend_on_package_body=self._simulator_factory.package_users_depend_on_bodies())

    def _create_database(self):
        """
        Create a persistent database to store expensive parse results

        Check for Python version used to create the database is the
        same as the running python instance or re-create
        """
        project_database_file_name = join(self._output_path, "project_database")
        create_new = False
        key = b"version"
        version = str((6, sys.version)).encode()
        database = None
        try:
            database = DataBase(project_database_file_name)
            create_new = (key not in database) or (database[key] != version)
        except KeyboardInterrupt:
            raise
        except:  # pylint: disable=bare-except
            traceback.print_exc()
            create_new = True

        if create_new:
            database = DataBase(project_database_file_name, new=True)
        database[key] = version

        return PickledDataBase(database)

    @staticmethod
    def _configure_logging(log_level):
        """
        Configure logging based on log_level string
        """
        level = getattr(logging, log_level.upper())
        logging.basicConfig(filename=None, format='%(levelname)7s - %(message)s', level=level)

    def add_external_library(self, library_name, path):
        """
        Add an externally compiled library as a black-box

        :param library_name: The name of the external library
        :param path: The path to the external library
        :returns: The created :class:`.Library` object

        :example:

        .. code-block:: python

           prj.add_external_library("unisim", "path/to/unisim/")

        """
        self._project.add_library(library_name, abspath(path), is_external=True)
        return self._create_library_facade(library_name)

    def add_library(self, library_name):
        """
        Add a library managed by VUnit.

        :param library_name: The name of the library
        :returns: The created :class:`.Library` object

        :example:

        .. code-block:: python

           library = prj.add_library("lib")

        """
        path = join(self._simulator_factory.simulator_output_path, "libraries", library_name)
        self._project.add_library(library_name, abspath(path))
        return self._create_library_facade(library_name)

    def library(self, library_name):
        """
        Get a library

        :param library_name: The name of the library
        :returns: A :class:`.Library` object
        """
        if not self._project.has_library(library_name):
            raise KeyError(library_name)
        return self._create_library_facade(library_name)

    def _create_library_facade(self, library_name):
        """
        Create a Library object to be exposed to users
        """
        return Library(library_name, self, self._project, self._configuration)

    def set_generic(self, name, value):
        """
        Globally set a value of generic

        :param name: The name of the generic
        :param value: The value of the generic

        :example:

        .. code-block:: python

           prj.set_generic("data_width", 16)

        """
        self._configuration.set_generic(name.lower(), value, scope=create_scope())

    def set_parameter(self, name, value):
        """
        Globally set value of parameter

        :param name: The name of the parameter
        :param value: The value of the parameter

        :example:

        .. code-block:: python

           prj.set_parameter("data_width", 16)

        """
        self._configuration.set_generic(name, value, scope=create_scope())

    def set_sim_option(self, name, value):
        """
        Globally set simulation option

        :param name: |simulation_options|
        :param value: The value of the simulation option

        :example:

        .. code-block:: python

           prj.set_sim_option("ghdl.flags", ["--no-vital-checks"])

        """
        self._configuration.set_sim_option(name, value, scope=create_scope())

    def set_compile_option(self, name, value):
        """
        Globally set compile option

        :param name: |compile_option|
        :param value: The value of the compile option

        :example:

        .. code-block:: python

           prj.set_compile_option("ghdl.flags", ["--no-vital-checks"])

        """
        for source_file in self._project.get_source_files_in_order():
            source_file.set_compile_option(name, value)

    def add_compile_option(self, name, value):
        """
        Globally add compile option

        :param name: |compile_option|
        :param value: The value of the compile option
        """
        for source_file in self._project.get_source_files_in_order():
            source_file.add_compile_option(name, value)

    def set_pli(self, value):
        """
        Globally Set pli

        :param value: A list of PLI object file names
        """
        self._configuration.set_pli(value, scope=create_scope())

    def disable_ieee_warnings(self):
        """
        Globally disable ieee warnings
        """
        self._configuration.disable_ieee_warnings(scope=create_scope())

    def get_source_file(self, file_name, library_name=None):
        """
        Get a source file

        :param file_name: The name of the file as a relative or absolute path
        :param library_name: The name of a specific library to search if not all libraries
        :returns: A :class:`.SourceFile` object
        """

        files = self.get_source_files(file_name, library_name, allow_empty=True)
        if len(files) > 1:
            raise ValueError("Found file named '%s' in multiple-libraries, "
                             "add explicit library_name." % file_name)
        elif len(files) == 0:
            if library_name is None:
                raise ValueError("Found no file named '%s'" % file_name)
            else:
                raise ValueError("Found no file named '%s' in library '%s'"
                                 % (file_name, library_name))
        return files[0]

    def get_source_files(self, pattern="*", library_name=None, allow_empty=False):
        """
        Get a list of source files

        :param pattern: A wildcard pattern matching either an absolute or relative path
        :param library_name: The name of a specific library to search if not all libraries
        :param allow_empty: To disable an error if no files matched the pattern
        :returns: A :class:`.SourceFileList` object
        """
        results = []
        for source_file in self._project.get_source_files_in_order():
            if library_name is not None:
                if source_file.library.name != library_name:
                    continue

            if not (fnmatch(abspath(source_file.name), pattern) or
                    fnmatch(ostools.simplify_path(source_file.name), pattern)):
                continue

            results.append(SourceFile(source_file, self._project, self))

        if (not allow_empty) and len(results) == 0:
            raise ValueError(("Pattern %r did not match any file. "
                              "Use allow_empty=True to avoid exception,") % pattern)

        return SourceFileList(results)

    def add_source_files(self,   # pylint: disable=too-many-arguments
                         files, library_name, preprocessors=None, include_dirs=None, defines=None, allow_empty=False):
        """
        Add source files matching wildcard pattern to library

        :param files: A wildcard pattern matching the files to add or a list of files
        :param library_name: The name of the library to add files into
        :param include_dirs: A list of include directories
        :param defines: A dictionary containing Verilog defines to be set
        :param allow_empty: To disable an error if no files matched the pattern
        :returns: A list of files (:class:`.SourceFileList`) which were added

        :example:

        .. code-block:: python

           prj.add_source_files("*.vhd", "lib")

        """
        if _is_iterable_not_string(files):
            files = [files]

        file_names = []
        for pattern in files:
            new_file_names = glob(pattern)

            if (not allow_empty) and len(new_file_names) == 0:
                raise ValueError(("Pattern %r did not match any file. "
                                  "Use allow_empty=True to avoid exception,") % pattern)
            file_names += new_file_names

        return SourceFileList(source_files=[
            self.add_source_file(file_name, library_name, preprocessors, include_dirs, defines)
            for file_name in file_names])

    def add_source_file(self, file_name, library_name, preprocessors=None, include_dirs=None, defines=None):
        """
        Add source file to library

        :param file_name: The name of the file
        :param library_name: The name of the library to add the file into
        :param include_dirs: A list of include directories
        :param defines: A dictionary containing Verilog defines to be set
        :returns: The :class:`.SourceFile` which was added

        :example:

        .. code-block:: python

           prj.add_source_file("file.vhd", "lib")

        """
        file_type = file_type_of(file_name)

        if file_type == "verilog":
            include_dirs = include_dirs if include_dirs is not None else []
            include_dirs = add_verilog_include_dir(include_dirs)

        file_name = self._preprocess(library_name, abspath(file_name), preprocessors)
        return SourceFile(self._project.add_source_file(file_name,
                                                        library_name,
                                                        file_type=file_type,
                                                        include_dirs=include_dirs,
                                                        defines=defines),
                          self._project,
                          self)

    def _preprocess(self, library_name, file_name, preprocessors):
        """
        Preprocess file_name within library_name using explicit preprocessors
        if preprocessors is None then use implicit globally defined processors
        """
        # @TODO dependency checking etc...

        if preprocessors is None:
            preprocessors = [self._location_preprocessor, self._check_preprocessor]
            preprocessors = [p for p in preprocessors if p is not None]
            preprocessors = self._external_preprocessors + preprocessors

        if len(preprocessors) == 0:
            return file_name

        code = ostools.read_file(file_name)
        for preprocessor in preprocessors:
            code = preprocessor.run(code, basename(file_name))

        pp_file_name = join(self._preprocessed_path, library_name, basename(file_name))

        idx = 1
        while ostools.file_exists(pp_file_name):
            LOGGER.debug("Preprocessed file exists '%s', adding prefix", pp_file_name)
            pp_file_name = join(self._preprocessed_path,
                                library_name, "%i_%s" % (idx, basename(file_name)))
            idx += 1

        ostools.write_file(pp_file_name, code)
        return pp_file_name

    def add_preprocessor(self, preprocessor):
        """
        Add a custom preprocessor to be used on all files, must be called before adding any files
        """
        self._external_preprocessors.append(preprocessor)

    def enable_location_preprocessing(self, additional_subprograms=None):
        """
        Enable location preprocessing, must be called before adding any files
        """
        preprocessor = LocationPreprocessor()
        if additional_subprograms is not None:
            for subprogram in additional_subprograms:
                preprocessor.add_subprogram(subprogram)
        self._location_preprocessor = preprocessor

    def enable_check_preprocessing(self):
        """
        Enable check preprocessing, must be called before adding any files
        """
        self._check_preprocessor = CheckPreprocessor()

    def main(self):
        """
        Run vunit main function and exit
        """
        try:
            all_ok = self._main()
        except KeyboardInterrupt:
            exit(1)
        except CompileError:
            exit(1)
        except TestScannerError:
            exit(1)
        except SystemExit:
            exit(1)
        except:  # pylint: disable=bare-except
            traceback.print_exc()
            exit(1)

        if (not all_ok) and (not self._exit_0):
            exit(1)

        exit(0)

    def _main(self):
        """
        Base vunit main function without performing exit
        """
        if self._list_only:
            return self._main_list_only()

        if self._list_files_only:
            return self._main_list_files_only()

        if self._compile_only:
            return self._main_compile_only()

        simulator_if = self._create_simulator_if()
        test_cases = self._create_tests(simulator_if)

        self._compile(simulator_if)

        start_time = ostools.get_time()
        report = TestReport(printer=self._printer)
        try:
            self._run_test(test_cases, report)
            simulator_if.post_process(self._simulator_factory.simulator_output_path)
        except KeyboardInterrupt:
            print()
            LOGGER.debug("_main: Caught Ctrl-C shutting down")
        finally:
            del test_cases
            del simulator_if

        report.set_real_total_time(ostools.get_time() - start_time)
        self._post_process(report)

        return report.all_ok()

    def _main_list_only(self):
        """
        Main function when only listing test cases
        """
        simulator_if = None
        test_suites = self._create_tests(simulator_if)

        for test_suite in test_suites:
            for name in test_suite.test_cases:
                print(name)
        print("Listed %i tests" % test_suites.num_tests())
        return True

    def _main_list_files_only(self):
        """
        Main function when only listing files
        """
        files = self.get_compile_order()
        for source_file in files:
            print("%s, %s" % (source_file.library.name, source_file.name))
        print("Listed %i files" % len(files))
        return True

    def _main_compile_only(self):
        """
        Main function when only compiling
        """
        simulator_if = self._create_simulator_if()
        self._compile(simulator_if)
        return True

    def _create_output_path(self, clean):
        """
        Create or re-create the output path if necessary
        """
        if clean:
            ostools.renew_path(self._output_path)
        elif not exists(self._output_path):
            os.makedirs(self._output_path)

        ostools.renew_path(self._preprocessed_path)

    def _create_simulator_if(self):
        """
        Create a simulator interface instance
        """
        return self._simulator_factory.create()

    @property
    def vhdl_standard(self):
        return self._vhdl_standard

    @property
    def _preprocessed_path(self):
        return join(self._output_path, "preprocessed")

    @property
    def codecs_path(self):
        return join(self._output_path, "codecs")

    @property
    def use_debug_codecs(self):
        return self._use_debug_codecs

    def _create_tests(self, simulator_if):
        """
        Create the test suites by scanning the project
        """
        scanner = TestScanner(simulator_if,
                              self._configuration,
                              elaborate_only=self._elaborate_only)
        test_list = scanner.from_project(self._project, entity_filter=self._tb_filter)

        if test_list.num_tests() == 0:
            LOGGER.warning("Test scanner found no test benches using current filter rule:\n%s",
                           self._tb_filter.__doc__)

        test_list.keep_matches(self._test_filter)
        return test_list

    def _compile(self, simulator_if):
        """
        Compile entire project
        """
        simulator_if.compile_project(self._project, self._vhdl_standard,
                                     continue_on_error=self._keep_compiling)

    def _run_test(self, test_cases, report):
        """
        Run the test suites and return the report
        """
        runner = TestRunner(report,
                            join(self._output_path, "tests"),
                            verbose=self._verbose,
                            num_threads=self._num_threads)
        runner.run(test_cases)

    def _post_process(self, report):
        """
        Print the report to stdout and optionally write it to an XML file
        """
        report.print_str()

        if self._xunit_xml is not None:
            xml = report.to_junit_xml_str()
            ostools.write_file(self._xunit_xml, xml)

    def add_builtins(self, library_name="vunit_lib", mock_lang=False, mock_log=False):
        """
        Add vunit VHDL builtin libraries
        """
        library = self.add_library(library_name)
        supports_context = self._simulator_factory.supports_vhdl_2008_contexts()
        add_vhdl_builtins(library, self._vhdl_standard, mock_lang, mock_log,
                          supports_context=supports_context)

    def add_com(self, library_name="vunit_lib", use_debug_codecs=None):
        """
        Add communication package

        :param use_debug_codecs: Use human readable debug codecs

           `None`: Use command line argument setting

           `False`: Never use debug codecs

           `True`: Always use debug codecs
        """
        if not self._project.has_library(library_name):
            library = self.add_library(library_name)
        else:
            library = self.library(library_name)

        if use_debug_codecs is not None:
            self._use_debug_codecs = use_debug_codecs

        supports_context = self._simulator_factory.supports_vhdl_2008_contexts()

        add_com(library, self._vhdl_standard,
                use_debug_codecs=self._use_debug_codecs,
                supports_context=supports_context)

    def add_array_util(self, library_name="vunit_lib"):
        """
        Add array utility package
        """
        library = self.library(library_name)
        add_array_util(library, self._vhdl_standard)

    def add_osvvm(self, library_name="osvvm"):
        """
        Add osvvm library
        """
        if not self._project.has_library(library_name):
            library = self.add_library(library_name)
        else:
            library = self.library(library_name)
        add_osvvm(library)

    def get_compile_order(self, source_files=None):
        """
        Get the compile order of all or specific source files and
        their dependencies

        :param source_files: A list of :class:`.SourceFile` objects or `None` meaing all
        :returns: A list of :class:`.SourceFile` objects in compile order.
        """
        if source_files is None:
            source_files = self.get_source_files()

        target_files = [source_file._source_file  # pylint: disable=protected-access
                        for source_file in source_files]
        source_files = self._project.get_dependencies_in_compile_order(target_files)
        return SourceFileList([SourceFile(source_file, self._project, self)
                               for source_file in source_files])