Пример #1
0
def test_given_call_tree_depth_of_two__dump_returns_extected_output():
    manager = CallTreeManager()
    excepted = 'f()\n  g()\n'
    with generate_file('two-functions.cpp',
                       'void g() {}\nvoid f() {g();}') as file_name:
        actual = manager.dump(file_name, 'f()')
    assert actual == excepted
Пример #2
0
def main():
    parser = OptionParser(
        'usage: %prog [options] entry-point {file.cpp|compile_commands.json} [extra-clang-args*]'
    )
    parser.add_option(
        '',
        '--include-system-headers',
        action="store_true",
        dest='include_system_headers',
        default=False,
        help='Include calls into system headers from the call-tree')
    # parser.add_option('', '--max-depth', dest='maxDepth',
    #                   help='Limit cursor expansion to depth N',
    #                   metavar='N', type=int, default=None)
    parser.disable_interspersed_args()
    (opts, args) = parser.parse_args()

    if len(args) < 2:
        parser.error('invalid number arguments')

    manager = CallTreeManager()
    extra_arguments = args[2:] if len(args) > 2 else None
    print(
        manager.dump(entry_point=args[0],
                     file_name=args[1],
                     include_system_headers=opts.include_system_headers,
                     extra_arguments=extra_arguments))
Пример #3
0
def test_given_tu_with_include__select_tu_returns_only_callables_in_main_file(
):
    manager = CallTreeManager()
    with generate_file('include.h', 'void f() {}') as include_file_name:
        with generate_file(
                'main_file.cpp', '#include "{}"\nvoid g();'.format(
                    include_file_name)) as main_file_name:
            manager.open(main_file_name)
            callable_list = manager.select_tu(main_file_name)
    assert len(callable_list) == 1
Пример #4
0
def test_given_no_callable_included__export_returns_empty_diagram():
    manager = CallTreeManager()
    with generate_file('file.cpp',
                       'void f();\nvoid g() { f(); }') as file_name:
        manager.open(file_name)
        manager.select_tu(file_name)
    manager.select_root('g()')
    expected = '@startuml\n\n\n@enduml'
    actual = manager.export()
    assert actual == expected
Пример #5
0
def test_given_werror_extra_argument_and_tu_with_unused_parameter__select_tu_fails(
):
    manager = CallTreeManager()
    manager.set_extra_arguments('-Werror -Wunused-parameter')
    with generate_file('file.cpp', 'void f(int i) {}') as file_name:
        with pytest.raises(SyntaxError):
            manager.open(file_name)
            manager.select_tu(file_name)
Пример #6
0
def test_given_tu_with_tree_three_functions_deep__tree_of_select_root_on_middle_function_has_depth_two(
):
    manager = CallTreeManager()
    content = 'void f();\nvoid g() { f(); }\nvoid h() { g(); }\n'
    with generate_file('file.cpp', content) as file_name:
        manager.open(file_name)
        manager.select_tu(file_name)
        root = manager.select_root('g()')
    children = manager.get_calls_of(root.name)
    assert len(children) == 1
    grand_children = manager.get_calls_of(children[0].name)
    assert len(grand_children) == 0
Пример #7
0
def test_given_tu_with_two_functions__get_calls_of_returns_one_callable():
    manager = CallTreeManager()
    with generate_file('file.cpp',
                       'void f();\nvoid g() { f(); }') as file_name:
        manager.open(file_name)
        manager.select_tu(file_name)
    unexpected_children = manager.get_calls_of('f()')
    expected_children = manager.get_calls_of('g()')
    assert len(unexpected_children) == 0
    assert len(expected_children) == 1
Пример #8
0
    def __init__(self, parent=None):
        super(EntryDialog, self).__init__(parent)

        self.setupUi(self)

        # TODO(KNR): prevent editing the entry file and entry point lists

        self.manager_ = CallTreeManager()

        self.browse_compilation_database_button_.clicked.connect(
            self.on_browse)
        self.compilation_database_path_.editingFinished.connect(
            self.on_edit_db_path)
        self.extra_arguments_.editingFinished.connect(self.on_edit_extra_args)
        self.entry_files_ = QStandardItemModel(self.entry_file_list_)
        self.entry_file_list_.setModel(self.entry_files_)
        self.entry_file_selection_ = self.entry_file_list_.selectionModel()
        self.entry_file_selection_.currentChanged.connect(
            self.on_select_entry_file)
        self.entry_points_ = QStandardItemModel(self.entry_point_list_)
Пример #9
0
class EntryDialog(QDialog, Ui_EntryDialog):
    def __init__(self, parent=None):
        super(EntryDialog, self).__init__(parent)

        self.setupUi(self)

        # TODO(KNR): prevent editing the entry file and entry point lists

        self.manager_ = CallTreeManager()

        self.browse_compilation_database_button_.clicked.connect(
            self.on_browse)
        self.compilation_database_path_.editingFinished.connect(
            self.on_edit_db_path)
        self.extra_arguments_.editingFinished.connect(self.on_edit_extra_args)
        self.entry_files_ = QStandardItemModel(self.entry_file_list_)
        self.entry_file_list_.setModel(self.entry_files_)
        self.entry_file_selection_ = self.entry_file_list_.selectionModel()
        self.entry_file_selection_.currentChanged.connect(
            self.on_select_entry_file)
        self.entry_points_ = QStandardItemModel(self.entry_point_list_)

    def on_edit_extra_args(self):
        args = self.extra_arguments_.text()
        self.manager_.state_ = CallTreeManagerState.INITIALIZED  # TODO(KNR): yuck
        self.manager_.set_extra_arguments(args)
        if self.compilation_database_path_.text():
            self.on_edit_db_path()

    def on_browse(self):
        path = QFileDialog.getOpenFileName(self, 'Open compilation database',
                                           '', '*.json')
        if path and len(path) > 0:
            path = path[0]
            if not path:
                return
            self.compilation_database_path_.setText(
                path)  # TODO(KNR): prevent double-event
            self.set_db_path(path)

    def on_edit_db_path(self):
        path = self.compilation_database_path_.text()
        if not path:
            return
        self.set_db_path(path)

    def set_db_path(self, db_path):
        compilation_database_directory = os.path.dirname(db_path)
        os.chdir(compilation_database_directory)
        self.entry_points_.clear()
        self.entry_files_.clear()
        tu_list = self.manager_.open(db_path)
        common_path = os.path.commonprefix(list(tu_list))
        for tu in tu_list:
            item = QStandardItem(tu.replace(common_path, ''))
            item.setData(tu)
            self.entry_files_.appendRow(item)

    def on_select_entry_file(self, current, previous):
        if not current:
            return
        entry_file_path = self.entry_files_.item(current.row(), 0).data()
        callable_list = self.manager_.select_tu(entry_file_path)
        self.entry_points_.clear()
        for callable in callable_list:
            item = CallableItem(callable)
            self.entry_points_.appendRow(item)
        self.entry_point_list_.setModel(self.entry_points_)

    def reject(self):
        QApplication.instance().quit()

    def accept(self):
        if not self.entry_point_list_.selectionModel():
            return
        current = self.entry_point_list_.selectionModel().selectedIndexes()
        if current and len(current) > 0:
            entry_point = self.entry_points_.item(current[0].row(), 0)
            self.manager_.select_root(entry_point.callable.name)
            self.hide()
            self.window_ = DiagramConfiguration(self.manager_, entry_point)
            self.window_.show()
Пример #10
0
def test_given_tu_referencing_function_in_other_tu__load_definition_grows_call_tree(
):
    manager = CallTreeManager()
    with generate_file('g.cpp',
                       'extern void f();\nvoid g() { f(); }') as file_name:
        manager.open(file_name)
        manager.select_tu(file_name)
        root = manager.select_root('g()')
    with generate_file('f.cpp', 'void f() { f(); }\n') as file_name:
        manager.state_ = CallTreeManagerState.READY_TO_SELECT_TU
        manager.open(
            file_name)  # TODO(KNR): a hack, use a compilation DB instead
        manager.load_definition('f()')
    children = manager.get_calls_of(root.name)
    grand_children = manager.get_calls_of(children[0].name)
    assert len(grand_children) == 1
Пример #11
0
def test_given_tu_with_one_function__select_tu_returns_list_with_one_item():
    manager = CallTreeManager()
    with generate_file('file.cpp', 'void f();') as file_name:
        manager.open(file_name)
        callable_list = manager.select_tu(file_name)
    assert len(callable_list) == 1
Пример #12
0
def test_given_source_file__open_returns_tu_list_with_one_item():
    manager = CallTreeManager()
    with generate_file('file.cpp', '') as file_name:
        tu_list = manager.open(file_name)
    assert len(tu_list) == 1
Пример #13
0
def test_given_methods_of_same_class__use_class_as_participant():
    manager = CallTreeManager()
    with generate_file('file.cpp',
                       'class Foo {\nvoid bar();\nvoid baz() { bar(); }\n};'
                       ) as file_name:
        manager.open(file_name)
        manager.select_tu(file_name)
    manager.select_root('Foo::baz()')
    manager.include('Foo::baz()')
    manager.include('Foo::bar()')
    expected = '@startuml\n\n -> "Foo": baz()\nactivate "Foo"\n"Foo" -> "Foo": bar()\nactivate "Foo"\ndeactivate "Foo"\ndeactivate "Foo"\n\n@enduml'
    actual = manager.export()
    assert actual == expected
Пример #14
0
def test_given_call_graph_of_depth_two__functions_exported_depth_first():
    manager = CallTreeManager()
    with generate_file(
            'file.cpp',
            'void i();\nvoid h();\nvoid g() { h(); }\nvoid f() { g();\ni(); }'
    ) as file_name:
        manager.open(file_name)
        manager.select_tu(file_name)
    manager.select_root('f()')
    manager.include('f()')
    manager.include('g()')
    manager.include('h()')
    manager.include('i()')
    expected = '@startuml\n\n -> "file.cpp": f()\nactivate "file.cpp"\n"file.cpp" -> "file.cpp": g()\nactivate "file.cpp"\n"file.cpp" -> "file.cpp": h()\nactivate "file.cpp"\ndeactivate "file.cpp"\ndeactivate "file.cpp"\n"file.cpp" -> "file.cpp": i()\nactivate "file.cpp"\ndeactivate "file.cpp"\ndeactivate "file.cpp"\n\n@enduml'
    actual = manager.export()
    assert actual == expected
Пример #15
0
def test_given_included_function_excluded_again__export_returns_diagram_with_call(
):
    manager = CallTreeManager()
    with generate_file('file.cpp',
                       'void f();\nvoid g() { f(); }') as file_name:
        manager.open(file_name)
        manager.select_tu(file_name)
    manager.select_root('g()')
    manager.include('g()')
    manager.include('f()')
    manager.exclude('g()')
    expected = '@startuml\n\n -> "file.cpp": f()\nactivate "file.cpp"\ndeactivate "file.cpp"\n\n@enduml'
    actual = manager.export()
    assert actual == expected
Пример #16
0
# Copyright (C) 2020 R. Knuus

from INCode.call_tree_manager import CallTreeManager
from INCode.tui import TuiViewModel
from prompt_toolkit.history import FileHistory
import appdirs
import click
import click_repl
import os
import re

manager = CallTreeManager()
root_callable = None
view_model = TuiViewModel(manager)


def clean_up_usage_message_(message, command):
    '''Convert application help message into command help message.'''
    return re.sub(
        '  --help\\s+Show this message and exit.', '\n',
        message.replace('Usage: {}'.format(os.path.basename(__file__)),
                        '').replace('  help', command))


@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
    '''Pleasantries CLI'''
    if ctx.invoked_subcommand is None:
        ctx.invoke(repl)