def test_cmd_pipeline(self):
        log_file = tempfile.mktemp(prefix='build-log')
        pre_graph_file = tempfile.mktemp(prefix='pre-graph')
        graph_file = tempfile.mktemp(prefix='graph')
        try:
            with open(log_file, 'w') as output_file:
                output_file.write(self._BUILD_LOG)

            interpreter = Interpreter()
            interpreter.onecmd('parse_vs_log %s' % log_file)
            interpreter.onecmd('store %s' % pre_graph_file)

            result = DependencyGraph.read(pre_graph_file)
            self.assertTrue(result.has_node('test.cpp'))
            self.assertTrue(result.has_node('test.hpp'))
            self.assertTrue(result.has_node('test2.hpp'))
            self.assertTrue(result.has_node('test-lib.hpp'))
            self.assertTrue(result.has_node('vector'))
            self.assertTrue(result.has_node('xmemory'))
            self.assertTrue(result.has_node('stdafx.cpp'))
            self.assertTrue(result.has_node('stdafx.h'))
            self.assertTrue(result.has_node('test-lib2.hpp'))
            self.assertTrue(result.has_node('memory'))

            interpreter_load_store = Interpreter()
            interpreter_load_store.onecmd(r'load %s' % pre_graph_file)
            interpreter_load_store.onecmd(r'remove_thirdparty_dependencies D:/work/test')
            interpreter_load_store.onecmd(r'store %s' % graph_file)

            result = DependencyGraph.read(graph_file)
            self.assertTrue(result.has_node('test.cpp'))
            self.assertTrue(result.has_node('test.hpp'))
            self.assertTrue(result.has_node('test2.hpp'))
            self.assertTrue(result.has_node('test-lib.hpp'))
            self.assertTrue(result.has_node('vector'))
            self.assertTrue(result.has_node('stdafx.cpp'))
            self.assertTrue(result.has_node('stdafx.h'))
            self.assertTrue(result.has_node('test-lib2.hpp'))
            self.assertTrue(result.has_node('memory'))
            self.assertFalse(result.has_node('xmemory'))
        finally:
            if os.path.exists(log_file):
                os.unlink(log_file)
            if os.path.exists(pre_graph_file):
                os.unlink(pre_graph_file)
            if os.path.exists(graph_file):
                os.unlink(graph_file)
示例#2
0
    def test_subgraph_dependencies(self):
        depgraph = DependencyGraph()
        depgraph.add_top_level_node('a.cpp')
        depgraph.add_dependency_node('a.cpp', 'a.hpp')
        depgraph.add_dependency_node('a.cpp', 'b.hpp')
        depgraph.add_dependency_node('a.cpp', 'c.hpp')
        depgraph.add_dependency_node('b.hpp', 'c.hpp')

        subgraph = depgraph.get_subgraph('b.hpp', True, False)

        self.assertEqual(
            sorted(subgraph._graph.nodes()),
            sorted([DependencyGraph.ROOT_NODE_LABEL, 'b.hpp', 'c.hpp']))
        self.assertEqual(
            sorted(subgraph._graph.edges()),
            sorted([(DependencyGraph.ROOT_NODE_LABEL, 'b.hpp'),
                    ('b.hpp', 'c.hpp')]))
示例#3
0
    def test_adds_top_level_nodes(self):
        depgraph = DependencyGraph()
        depgraph.add_top_level_node('a.cpp', strattr='value', intattr=2)
        depgraph.add_top_level_node('b.cpp', floatattr=3.5)

        with self.assertRaisesRegex(RuntimeError,
                                    r'^Duplicated node for label "a\.cpp"'):
            depgraph.add_top_level_node('a.cpp')

        graph = depgraph._graph
        nodes = graph.nodes()
        self.assertEqual(len(nodes), 3)
        self.assertIn(depgraph.ROOT_NODE_LABEL, nodes)
        self.assertIn('a.cpp', nodes)
        self.assertEqual(graph.node['a.cpp']['strattr'], 'value')
        self.assertEqual(graph.node['a.cpp']['intattr'], 2)
        self.assertIn('b.cpp', nodes)
        self.assertEqual(graph.node['b.cpp']['floatattr'], 3.5)

        self.assertEqual(len(graph.edges()), 2)
        self.assertTrue(graph.has_edge(depgraph.ROOT_NODE_LABEL, 'a.cpp'))
        self.assertTrue(graph.has_edge(depgraph.ROOT_NODE_LABEL, 'b.cpp'))
示例#4
0
 def test_attribute_access(self):
     depgraph = DependencyGraph()
     depgraph.add_top_level_node('a.cpp', intattr=0)
     self.assertEqual(depgraph.get_attribute('a.cpp', 'intattr'), 0)
     self.assertFalse(depgraph.has_attribute('a.cpp', 'charattr'))
     self.assertIsNone(depgraph.get_attribute('a.cpp', 'charattr'))
     depgraph.set_attribute('a.cpp', 'charattr', 'a')
     self.assertTrue(depgraph.has_attribute('a.cpp', 'charattr'))
     depgraph.set_attribute('a.cpp', 'intattr', 1)
     self.assertEqual(depgraph.get_attribute('a.cpp', 'intattr'), 1)
     self.assertEqual(depgraph.get_attribute('a.cpp', 'charattr'), 'a')
示例#5
0
    def test_reads_writes_to_file(self):
        depgraph = DependencyGraph()
        depgraph.add_top_level_node('a.cpp')
        depgraph.add_dependency_node('a.cpp', 'a.h', intattr=3)
        depgraph.add_dependency_node('a.cpp', 'aa.h')

        depgraph.add_top_level_node('b.cpp', floatattr=3.5)
        depgraph.add_dependency_node('b.cpp', 'b.h')
        depgraph.add_dependency_node('b.h', 'bb.h')
        depgraph.add_dependency_node('b.h', 'a.h', floatattr=1.2)

        path = tempfile.mktemp()
        try:
            depgraph.write(path)
            read = depgraph.read(path)
        finally:
            os.remove(path)

        self.assertEqual(sorted(depgraph._graph.nodes(data=True)),
                         sorted(read._graph.nodes(data=True)))
        self.assertEqual(sorted(depgraph._graph.edges(data=True)),
                         sorted(read._graph.edges(data=True)))
示例#6
0
    def test_adds_dependency_nodes(self):
        depgraph = DependencyGraph()
        depgraph.add_top_level_node('a.cpp')
        depgraph.add_dependency_node('a.cpp', 'a.h', intattr=3)
        depgraph.add_dependency_node('a.cpp', 'aa.h')

        depgraph.add_top_level_node('b.cpp', floatattr=3.5)
        depgraph.add_dependency_node('b.cpp', 'b.h')
        depgraph.add_dependency_node('b.h', 'bb.h')
        depgraph.add_dependency_node('b.h', 'a.h', floatattr=1.2)

        with self.assertRaisesRegex(
                RuntimeError, r'Dependency node parent "c.cpp" not found '
                r'for label "c.h"'):
            depgraph.add_dependency_node('c.cpp', 'c.h')

        graph = depgraph._graph
        nodes = graph.nodes()
        self.assertEqual(len(nodes), 7)
        self.assertIn(depgraph.ROOT_NODE_LABEL, nodes)
        self.assertIn('a.cpp', nodes)
        self.assertIn('a.h', nodes)
        self.assertEqual(graph.node['a.h']['intattr'], 3)
        self.assertEqual(graph.node['a.h']['floatattr'], 1.2)
        self.assertIn('aa.h', nodes)
        self.assertIn('b.cpp', nodes)
        self.assertIn('b.h', nodes)
        self.assertIn('bb.h', nodes)

        self.assertEqual(len(graph.edges()), 7)
        self.assertTrue(graph.has_edge(depgraph.ROOT_NODE_LABEL, 'a.cpp'))
        self.assertTrue(graph.has_edge(depgraph.ROOT_NODE_LABEL, 'b.cpp'))
        self.assertTrue(graph.has_edge('a.cpp', 'a.h'))
        self.assertTrue(graph.has_edge('a.cpp', 'aa.h'))
        self.assertTrue(graph.has_edge('b.cpp', 'b.h'))
        self.assertTrue(graph.has_edge('b.h', 'bb.h'))
        self.assertTrue(graph.has_edge('b.h', 'a.h'))
示例#7
0
    def test_removes_dependencies_by_predicate(self):
        depgraph = DependencyGraph()
        depgraph.add_top_level_node('bad-parent')
        depgraph.add_top_level_node('good-parent')
        depgraph.add_dependency_node('bad-parent', 'child-1', good=False)
        depgraph.add_dependency_node('good-parent', 'child-1', good=False)
        depgraph.add_dependency_node('bad-parent', 'child-2', good=True)
        depgraph.add_dependency_node('good-parent', 'child-2', good=False)

        depgraph.remove_dependency_by_predicate(
            lambda parent, child: parent == 'bad-parent' and depgraph.
            get_attribute(child, 'good', True) == False)
class TestAnalysis(unittest.TestCase):
    def _create_file(self, prefix, size):
        filename = tempfile.mktemp(prefix=prefix)
        with open(filename, 'w') as output_file:
            output_file.write('.' * size)
        self._files[prefix] = filename
        return filename

    def setUp(self):
        '''
        The test dependency graph is setup as follows:

        pch.cpp [file size: 10B, build time: 10.0, create pch: pch.h]
        - pch.h [file size: 50B]
        -- lib.hpp [file size: 20B]
        a.cpp [file size: 100B, build time: 3.0]
        - other.hpp [file size: 50B]
        - a.hpp [file size: 10B]
        -- lib.hpp [file size: 20B]
        b.cpp [file size: 30B, build time: 5.0, uses pch: pch.h]
        - other.hpp [file size: 50B]
        - pch.h [file size: 50B]
        -- lib.hpp [file size: 20B]
        '''
        self._files = {}
        self._dependency_graph = DependencyGraph()

        self._dependency_graph.add_top_level_node(
            'pch.cpp', **{
                Analyser.Attributes.BUILD_TIME: 10.0,
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('pch.cpp', 10),
                Analyser.Attributes.CREATED_PCH: 'pch.h'
            })
        self._dependency_graph.add_dependency_node(
            'pch.cpp', 'pch.h', **{
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('pch.h', 50)
            })

        self._dependency_graph.add_top_level_node(
            'a.cpp', **{
                Analyser.Attributes.BUILD_TIME: 3.0,
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('a.cpp', 100)
            })
        self._dependency_graph.add_dependency_node(
            'a.cpp', 'other.hpp', **{
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('other.hpp', 50)
            })
        self._dependency_graph.add_dependency_node(
            'a.cpp', 'a.hpp', **{
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('a.hpp', 10)
            })
        libhpp_path = self._create_file('lib.hpp', 20)
        self._dependency_graph.add_dependency_node(
            'a.hpp', 'lib.hpp',
            **{Analyser.Attributes.ABSOLUTE_PATH: libhpp_path})

        self._dependency_graph.add_top_level_node(
            'b.cpp', **{
                Analyser.Attributes.BUILD_TIME: 5.0,
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('b.cpp', 30),
                Analyser.Attributes.USED_PCH: 'pch.h'
            })
        self._dependency_graph.add_dependency_node(
            'b.cpp', 'pch.h', **{
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('pch.h', 50)
            })
        self._dependency_graph.add_dependency_node(
            'pch.h', 'lib.hpp',
            **{Analyser.Attributes.ABSOLUTE_PATH: libhpp_path})
        self._dependency_graph.add_dependency_node(
            'b.cpp', 'other.hpp', **{
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('other.hpp', 50)
            })

    def tearDown(self):
        for output_file in self._files.values():
            os.unlink(output_file)

    def test_individual_file_sizes(self):
        analyser = Analyser(self._dependency_graph)
        analyser.calculate_file_sizes()

        self.assertEqual(
            self._dependency_graph.get_attribute(
                'pch.cpp', Analyser.Attributes.FILE_SIZE), 10)
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'pch.h', Analyser.Attributes.FILE_SIZE), 50)
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'lib.hpp', Analyser.Attributes.FILE_SIZE), 20)

        self.assertEqual(
            self._dependency_graph.get_attribute(
                'a.cpp', Analyser.Attributes.FILE_SIZE), 100)
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'a.hpp', Analyser.Attributes.FILE_SIZE), 10)

        self.assertEqual(
            self._dependency_graph.get_attribute(
                'b.cpp', Analyser.Attributes.FILE_SIZE), 30)
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'other.hpp', Analyser.Attributes.FILE_SIZE), 50)

    def test_total_file_sizes(self):
        # adding dependency between b.cpp and a.hpp to check if a.hpp cashes in differently
        # when lib.hpp is added through a pch file
        self._dependency_graph.add_dependency_node('b.cpp', 'a.hpp')

        analyser = Analyser(self._dependency_graph)
        analyser.calculate_file_sizes()
        analyser.calculate_total_sizes()

        self.assertEqual(
            self._dependency_graph.get_attribute(
                'pch.cpp', Analyser.Attributes.TOTAL_SIZE), 10 + 50 + 20)
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'pch.h', Analyser.Attributes.TOTAL_SIZE), 50 + 20)
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'lib.hpp', Analyser.Attributes.TOTAL_SIZE), 20 + 20)

        self.assertEqual(
            self._dependency_graph.get_attribute(
                'a.cpp', Analyser.Attributes.TOTAL_SIZE), 100 + 10 + 20 + 50)
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'a.hpp', Analyser.Attributes.TOTAL_SIZE), 10 + 20 + 10)

        self.assertEqual(
            self._dependency_graph.get_attribute(
                'b.cpp', Analyser.Attributes.TOTAL_SIZE),
            30 + 10 + 50)  # pch.h and lib.hpp not added
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'other.hpp', Analyser.Attributes.TOTAL_SIZE), 50 + 50)

    def test_total_file_sizes_no_redundant(self):
        depgraph = DependencyGraph()
        depgraph.add_top_level_node('a.cpp',
                                    **{Analyser.Attributes.FILE_SIZE: 1})
        depgraph.add_dependency_node('a.cpp', 'a.h',
                                     **{Analyser.Attributes.FILE_SIZE: 1})
        depgraph.add_dependency_node('a.h', 'aa.h',
                                     **{Analyser.Attributes.FILE_SIZE: 1})
        depgraph.add_dependency_node('a.cpp', 'aa.h',
                                     **{Analyser.Attributes.FILE_SIZE: 1})

        analyser = Analyser(depgraph)
        analyser.calculate_total_sizes()

        self.assertEqual(
            depgraph.get_attribute(DependencyGraph.ROOT_NODE_LABEL,
                                   Analyser.Attributes.TOTAL_SIZE), 3)
        self.assertEqual(
            depgraph.get_attribute('a.cpp', Analyser.Attributes.TOTAL_SIZE), 3)
        self.assertEqual(
            depgraph.get_attribute('a.h', Analyser.Attributes.TOTAL_SIZE), 2)
        self.assertEqual(
            depgraph.get_attribute('aa.h', Analyser.Attributes.TOTAL_SIZE), 1)

    def test_total_build_times(self):
        analyser = Analyser(self._dependency_graph)
        analyser.calculate_total_build_times()

        self.assertEqual(
            self._dependency_graph.get_attribute(
                'pch.h', Analyser.Attributes.BUILD_TIME),
            10.0)  # b.cpp not added
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'lib.hpp', Analyser.Attributes.BUILD_TIME),
            10.0 + 3.0)  # b.cpp not added

        self.assertAlmostEqual(
            self._dependency_graph.get_attribute(
                'a.hpp', Analyser.Attributes.BUILD_TIME), 3.0)

        self.assertEqual(
            self._dependency_graph.get_attribute(
                'other.hpp', Analyser.Attributes.BUILD_TIME), 3.0 + 5.0)

    def test_translation_units(self):
        analyser = Analyser(self._dependency_graph)
        analyser.calculate_translation_units()

        self.assertEqual(
            self._dependency_graph.get_attribute(
                DependencyGraph.ROOT_NODE_LABEL,
                Analyser.Attributes.TRANSLATION_UNITS), 3)

        self.assertFalse(
            self._dependency_graph.has_attribute(
                'pch.cpp', Analyser.Attributes.TRANSLATION_UNITS))
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'pch.h', Analyser.Attributes.TRANSLATION_UNITS),
            1)  # b.cpp not added
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'lib.hpp', Analyser.Attributes.TRANSLATION_UNITS),
            2)  # b.cpp not added

        self.assertFalse(
            self._dependency_graph.has_attribute(
                'a.cpp', Analyser.Attributes.TRANSLATION_UNITS))
        self.assertAlmostEqual(
            self._dependency_graph.get_attribute(
                'a.hpp', Analyser.Attributes.TRANSLATION_UNITS), 1)

        self.assertFalse(
            self._dependency_graph.has_attribute(
                'b.cpp', Analyser.Attributes.TRANSLATION_UNITS))
        self.assertEqual(
            self._dependency_graph.get_attribute(
                'other.hpp', Analyser.Attributes.TRANSLATION_UNITS), 2)
    def setUp(self):
        '''
        The test dependency graph is setup as follows:

        pch.cpp [file size: 10B, build time: 10.0, create pch: pch.h]
        - pch.h [file size: 50B]
        -- lib.hpp [file size: 20B]
        a.cpp [file size: 100B, build time: 3.0]
        - other.hpp [file size: 50B]
        - a.hpp [file size: 10B]
        -- lib.hpp [file size: 20B]
        b.cpp [file size: 30B, build time: 5.0, uses pch: pch.h]
        - other.hpp [file size: 50B]
        - pch.h [file size: 50B]
        -- lib.hpp [file size: 20B]
        '''
        self._files = {}
        self._dependency_graph = DependencyGraph()

        self._dependency_graph.add_top_level_node(
            'pch.cpp', **{
                Analyser.Attributes.BUILD_TIME: 10.0,
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('pch.cpp', 10),
                Analyser.Attributes.CREATED_PCH: 'pch.h'
            })
        self._dependency_graph.add_dependency_node(
            'pch.cpp', 'pch.h', **{
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('pch.h', 50)
            })

        self._dependency_graph.add_top_level_node(
            'a.cpp', **{
                Analyser.Attributes.BUILD_TIME: 3.0,
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('a.cpp', 100)
            })
        self._dependency_graph.add_dependency_node(
            'a.cpp', 'other.hpp', **{
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('other.hpp', 50)
            })
        self._dependency_graph.add_dependency_node(
            'a.cpp', 'a.hpp', **{
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('a.hpp', 10)
            })
        libhpp_path = self._create_file('lib.hpp', 20)
        self._dependency_graph.add_dependency_node(
            'a.hpp', 'lib.hpp',
            **{Analyser.Attributes.ABSOLUTE_PATH: libhpp_path})

        self._dependency_graph.add_top_level_node(
            'b.cpp', **{
                Analyser.Attributes.BUILD_TIME: 5.0,
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('b.cpp', 30),
                Analyser.Attributes.USED_PCH: 'pch.h'
            })
        self._dependency_graph.add_dependency_node(
            'b.cpp', 'pch.h', **{
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('pch.h', 50)
            })
        self._dependency_graph.add_dependency_node(
            'pch.h', 'lib.hpp',
            **{Analyser.Attributes.ABSOLUTE_PATH: libhpp_path})
        self._dependency_graph.add_dependency_node(
            'b.cpp', 'other.hpp', **{
                Analyser.Attributes.ABSOLUTE_PATH:
                self._create_file('other.hpp', 50)
            })
    def test_total_file_sizes_no_redundant(self):
        depgraph = DependencyGraph()
        depgraph.add_top_level_node('a.cpp',
                                    **{Analyser.Attributes.FILE_SIZE: 1})
        depgraph.add_dependency_node('a.cpp', 'a.h',
                                     **{Analyser.Attributes.FILE_SIZE: 1})
        depgraph.add_dependency_node('a.h', 'aa.h',
                                     **{Analyser.Attributes.FILE_SIZE: 1})
        depgraph.add_dependency_node('a.cpp', 'aa.h',
                                     **{Analyser.Attributes.FILE_SIZE: 1})

        analyser = Analyser(depgraph)
        analyser.calculate_total_sizes()

        self.assertEqual(
            depgraph.get_attribute(DependencyGraph.ROOT_NODE_LABEL,
                                   Analyser.Attributes.TOTAL_SIZE), 3)
        self.assertEqual(
            depgraph.get_attribute('a.cpp', Analyser.Attributes.TOTAL_SIZE), 3)
        self.assertEqual(
            depgraph.get_attribute('a.h', Analyser.Attributes.TOTAL_SIZE), 2)
        self.assertEqual(
            depgraph.get_attribute('aa.h', Analyser.Attributes.TOTAL_SIZE), 1)