Skip to content

Commit

Permalink
Add --export-json flag. #347
Browse files Browse the repository at this point in the history
  • Loading branch information
kraigher committed Sep 6, 2018
1 parent 81b22ad commit 95cc693
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 1 deletion.
59 changes: 59 additions & 0 deletions docs/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,62 @@ Further info:
* `Announcing Docker Enterprise Edition <https://blog.docker.com/2017/03/docker-enterprise-edition/>`_
* `Introducing Moby Project: a new open-source project to advance the software containerization movement <https://blog.docker.com/2017/04/introducing-the-moby-project/>`_
* If you don't want or cannot install docker, you can still use it online. `Play with Docker <https://play-with-docker.com>`_ (PWD) *"is a Docker playground which allows users to run Docker commands in a matter of seconds. It gives the experience of having a free Alpine Linux Virtual Machine in browser, where you can build and run Docker containers and even create clusters"*.


IDE Integration
---------------
VUnit supports IDE integration through the ``--export-json`` command
line argument. A JSON file is written containing the list of all files
added to the project as well as a list of all tests. Each test has a
mapping its source code location. Thus the IDE can know the path to
all files, the library mapping if files and the source code location
of all tests.

The JSON export file has three top level values:

- ``export_format_version``: The `semantic <https://semver.org/>`_ version of the format
- ``files``: List of project files. Each file item has ``file_name`` and ``library_name``.
- ``tests``: List of tests. Each test has ``file_name`` and ``lineo``.

.. code-block:: json
:caption: Example JSON export file (file names are always absolute but the example has been simplified)
{
"export_format_version": {
"major": 1,
"minor": 0,
"patch": 0
},
"files": [
{
"library_name": "lib",
"file_name": "tb_example_many.vhd"
},
{
"library_name": "lib",
"file_name": "tb_example.vhd"
}
],
"tests": [
{
"file_name": "tb_example_many.vhd",
"lineno": 22,
"file_name": "lib.tb_example_many.test_pass"
},
{
"file_name": "tb_example_many.vhd",
"lineno": 25,
"file_name": "lib.tb_example_many.test_fail"
},
{
"file_name": "tb_example.vhd",
"lineno": 18,
"file_name": "lib.tb_example.all"
}
]
}
.. note:: Several tests may map to the same source code location if
the user created multiple :ref:`configurations
<configurations>` of the same basic tests.
52 changes: 51 additions & 1 deletion vunit/test/unit/test_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@
from string import Template
import os
from os.path import join, dirname, basename, exists, abspath
import json
import re
from re import MULTILINE
from shutil import rmtree
from vunit.ui import VUnit
from vunit.project import VHDL_EXTENSIONS, VERILOG_EXTENSIONS
from vunit.test.mock_2or3 import mock
from vunit.test.common import set_env
from vunit.test.common import (set_env,
with_tempdir,
create_vhdl_test_bench_file)
from vunit.ostools import renew_path
from vunit.builtins import add_verilog_include_dir
from vunit.simulator_interface import SimulatorInterface
Expand Down Expand Up @@ -374,6 +377,53 @@ def test_list_files_flag(self):
lib1, ent0.vhd
Listed 2 files""".splitlines()))

@with_tempdir
def test_export_json(self, tempdir):
json_file = join(tempdir, "export.json")

ui = self._create_ui("--export-json", json_file)
lib1 = ui.add_library("lib1")
lib2 = ui.add_library("lib2")

file_name1 = join(tempdir, "tb_foo.vhd")
create_vhdl_test_bench_file("tb_foo", file_name1)
lib1.add_source_file(file_name1)

file_name2 = join(tempdir, "tb_bar.vhd")
create_vhdl_test_bench_file("tb_bar", file_name2,
tests=["Test one", "Test two"])
lib2.add_source_file(file_name2)

self._run_main(ui)

with open(json_file, "r") as fptr:
data = json.load(fptr)

# Check known keys
self.assertEqual(set(data.keys()),
set(["export_format_version",
"files",
"tests"]))

# Check that export format is semantic version with integer values
self.assertEqual(set(data["export_format_version"].keys()),
set(("major", "minor", "patch")))
assert all(isinstance(value, int)
for value in data["export_format_version"].values())

# Check the contents of the files section
self.assertEqual(set((item["library_name"], item["file_name"])
for item in data["files"]),
set([("lib1", abspath(file_name1)),
("lib2", abspath(file_name2))]))

# Check the contents of the tests section
self.assertEqual(set((item["name"], item["file_name"], item["lineno"])
for item in data["tests"]),
set([("lib1.tb_foo.all", file_name1, 12),
("lib2.tb_bar.Test one", file_name2, 13),
("lib2.tb_bar.Test two", file_name2, 14)]))

def test_library_attributes(self):
ui = self._create_ui()
lib1 = ui.add_library("lib1")
Expand Down
43 changes: 43 additions & 0 deletions vunit/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@
import sys
import traceback
import logging
import json
import os
from os.path import exists, abspath, join, basename, splitext, normpath, dirname
from glob import glob
Expand Down Expand Up @@ -790,6 +791,9 @@ def _main(self, post_run):
Base vunit main function without performing exit
"""

if self._args.export_json is not None:
return self._main_export_json(self._args.export_json)

if self._args.list:
return self._main_list_only()

Expand Down Expand Up @@ -857,6 +861,45 @@ def _main_list_only(self):
print("Listed %i tests" % test_list.num_tests)
return True

def _main_export_json(self, json_file_name):
"""
Main function when exporting to JSON
"""

file_objects = self.get_compile_order()
files = []
for source_file in file_objects:
files.append(dict(file_name=abspath(source_file.name),
library_name=source_file.library.name))

tests = []
for test_suite in self._create_tests(simulator_if=None):
test_locations = test_suite.test_locations
for name in test_suite.test_names:
file_name, lineno = test_locations[name]
tests.append(dict(name=name,
file_name=file_name,
lineno=lineno))

json_data = dict(
# The semantic version (https://semver.org/) of the JSON export data format
export_format_version=dict(major=1, minor=0, patch=0),

# The set of files added to the project
files=files,

# The list of all tests
tests=tests)

with open(json_file_name, "w") as fptr:
json.dump(json_data,
fptr,
sort_keys=True,
indent=4,
separators=(',', ': '))

return True

def _main_list_files_only(self):
"""
Main function when only listing files
Expand Down
4 changes: 4 additions & 0 deletions vunit/vunit_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ def _create_argument_parser(description=None, for_documentation=False):
nargs="?",
help="Enable code coverage. Works with ModelSim and RivieraPRO.")

parser.add_argument("--export-json",
default=None,
help="Export project information to a JSON file. Used for IDE integration.")

parser.add_argument('--version', action='version', version=version())

SIMULATOR_FACTORY.add_arguments(parser)
Expand Down

0 comments on commit 95cc693

Please sign in to comment.