Beispiel #1
0
def test_ControlFlowGraph_node_name_changes_hash():
    """Test that hash depends on node name."""
    g1 = control_flow_graph.ControlFlowGraph()
    g1.add_node(0, name="A", entry=True)

    g2 = control_flow_graph.ControlFlowGraph()
    g2.add_node(0, name="B", entry=True)

    assert hash(g1) != hash(g2)
Beispiel #2
0
def test_ControlFlowGraph_IsomorphicHash_equivalency():
    """Test equivalent hashes, despite different attributes."""
    # Graph 1: A --> B
    g1 = control_flow_graph.ControlFlowGraph(name="foo")
    g1.add_node(0, name="A", entry=True)
    g1.add_node(1, name="B", exit=True)
    g1.add_edge(0, 1)

    # Graph 2: C --> D
    g2 = control_flow_graph.ControlFlowGraph(name="bar")
    g2.add_node(0, name="C", entry=True)
    g2.add_node(1, name="D", exit=True)
    g2.add_edge(0, 1)

    assert g1.IsomorphicHash() == g2.IsomorphicHash()
Beispiel #3
0
def test_ControlFlowGraph_unequal_graph_names_are_equal():
    """Test that graph names are not used in comparison."""
    # Graph 1: A --> B
    g1 = control_flow_graph.ControlFlowGraph(name="foo")
    g1.add_node(0, name="A", entry=True)
    g1.add_node(1, name="B", exit=True)
    g1.add_edge(0, 1)

    # Graph 2: A --> B
    g2 = control_flow_graph.ControlFlowGraph(name="bar")
    g2.add_node(0, name="A", entry=True)
    g2.add_node(1, name="B", exit=True)
    g2.add_edge(0, 1)

    assert g1 == g2
Beispiel #4
0
def test_ControlFlowGraph_unequal_edge_data():
    """Test that edge data is used in comparison."""
    # Graph 1: A --> B
    g1 = control_flow_graph.ControlFlowGraph(name="foo")
    g1.add_node(0, name="A", exit=True)
    g1.add_node(1, name="B")
    g1.add_edge(0, 1)

    # Graph 2: A --> B
    g2 = control_flow_graph.ControlFlowGraph(name="bar")
    g2.add_node(0, name="A")
    g2.add_node(1, name="B", entry=True)
    g2.add_edge(0, 1)

    assert g1 != g2
Beispiel #5
0
def test_ControlFlowGraph_equal():
    """Test that equal graphs can be compared."""
    # Graph 1: A --> B
    g1 = control_flow_graph.ControlFlowGraph()
    g1.add_node(0, name="A", entry=True)
    g1.add_node(1, name="B", exit=True)
    g1.add_edge(0, 1)

    # Graph 2: A --> B
    g2 = control_flow_graph.ControlFlowGraph()
    g2.add_node(0, name="A", entry=True)
    g2.add_node(1, name="B", exit=True)
    g2.add_edge(0, 1)

    assert g1 == g2
Beispiel #6
0
def test_ControlFlowGraph_equivalent_hashes():
    """Test equivalent hashes, despite different graph names."""
    # Graph 1: A --> B
    g1 = control_flow_graph.ControlFlowGraph(name="foo")
    g1.add_node(0, name="A", entry=True)
    g1.add_node(1, name="B", exit=True)
    g1.add_edge(0, 1)

    # Graph 2: A --> B
    g2 = control_flow_graph.ControlFlowGraph(name="bar")
    g2.add_node(0, name="A", entry=True)
    g2.add_node(1, name="B", exit=True)
    g2.add_edge(0, 1)

    assert hash(g1) == hash(g2)
Beispiel #7
0
def test_ControlFlowGraph_unequal_edges():
    """Test that graphs with unequal edges are not equal."""
    # Graph 1: A --> B
    g1 = control_flow_graph.ControlFlowGraph()
    g1.add_node(0, name="A", entry=True)
    g1.add_node(1, name="B", exit=True)
    g1.add_edge(0, 1)

    # Graph 2: B --> A
    g2 = control_flow_graph.ControlFlowGraph()
    g2.add_node(0, name="A", entry=True)
    g2.add_node(1, name="B", exit=True)
    g2.add_edge(1, 0)

    assert g1 != g2
Beispiel #8
0
def test_ControlFlowGraph_edge_density():
    """Test edge density property."""
    # Graph:
    #
    #     +----> B -----+
    #     |             |
    #     |             v
    #     A             D
    #     |             ^
    #     |             |
    #     +----> C -----+
    g = control_flow_graph.ControlFlowGraph()
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="C")
    g.add_node(3, name="D", exit=True)
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 3)
    g.add_edge(2, 3)

    assert g.edge_density == pytest.approx(1 / 4)

    # Add A -> D path.
    g.add_edge(0, 3)
    assert g.edge_density == pytest.approx(5 / 16)
Beispiel #9
0
def test_ControlFlowGraph_validate_empty_graph():
    """Test that empty graph is invalid."""
    g = control_flow_graph.ControlFlowGraph()
    with test.Raises(control_flow_graph.NotEnoughNodes) as e_ctx:
        g.ValidateControlFlowGraph()
    assert str(e_ctx.value) == "Function `cfg` has no nodes"
    assert not g.IsValidControlFlowGraph()
Beispiel #10
0
def test_ControlFlowGraph_IsValidControlFlowGraph_irreducible_loop():
    """Test that an irreducible graph is valid."""
    g = control_flow_graph.ControlFlowGraph()
    # Graph:
    #              +-------+
    #              |       |
    #              v       |
    #     A------->B+----->C
    #     |        |       ^
    #     |        |       |
    #     |        v       |
    #     |        D       |
    #     |                |
    #     +----------------+
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="C")
    g.add_node(3, name="D", exit=True)
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 2)
    g.add_edge(2, 1)
    g.add_edge(1, 3)
    assert g.ValidateControlFlowGraph() == g
    assert g.IsValidControlFlowGraph()
Beispiel #11
0
def test_ControlFlowGraph_undirected_diameter():
    """Test undirected_diameter property."""
    # Graph:
    #
    #     +----> B -----+
    #     |             |
    #     |             v
    #     A             D
    #     |             ^
    #     |             |
    #     +----> C -----+
    g = control_flow_graph.ControlFlowGraph()
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="C")
    g.add_node(3, name="D", exit=True)
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 3)
    g.add_edge(2, 3)

    assert g.undirected_diameter == 2

    # Increase the diameter by adding a new E node and D -> E path.
    g.add_node(4, name="E")
    g.add_edge(3, 4)
    assert g.undirected_diameter == 3
Beispiel #12
0
def test_ControlFlowGraph_IsValidControlFlowGraph_exit_block_has_output():
    """Test that an if-else loop graph is valid."""
    g = control_flow_graph.ControlFlowGraph()
    # Graph:
    #
    #     +----> B -----+
    #     |             |
    #     |             v
    #     A<-----------+D
    #     |             ^
    #     |             |
    #     +----> C -----+
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="C")
    g.add_node(3, name="D", exit=True)
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 3)
    g.add_edge(2, 3)
    g.add_edge(3, 0)
    with test.Raises(control_flow_graph.InvalidNodeDegree) as e_ctx:
        g.ValidateControlFlowGraph()
    assert str(e_ctx.value) == "Exit block outdegree(D) = 1 in function `cfg`"
    assert not g.IsValidControlFlowGraph()
Beispiel #13
0
def test_ControlFlowGraph_node_attribute_changes_hash():
    """Test that hash depends on node attributes."""
    g1 = control_flow_graph.ControlFlowGraph()
    g1.add_node(0, name="A")

    g2 = g1.copy()
    assert hash(g1) == hash(g2)

    g2.nodes[0]["entry"] = True
    assert hash(g1) != hash(g2)
Beispiel #14
0
def test_ControlFlowGraph_IsValidControlFlowGraph_disconnected_graph():
    """A disconnected graph is not valid."""
    g = control_flow_graph.ControlFlowGraph()
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B", exit=True)
    g.add_node(2, name="C")
    g.add_edge(0, 1)
    with test.Raises(control_flow_graph.UnconnectedNode) as e_ctx:
        g.ValidateControlFlowGraph()
    assert str(e_ctx.value) == "Unconnected node 'C'"
    assert not g.IsValidControlFlowGraph()
Beispiel #15
0
def test_ControlFlowGraph_IsValidControlFlowGraph_no_path_from_entry_to_exit():
    """A disconnected graph is not valid."""
    # Graph: A -> B <- C
    g = control_flow_graph.ControlFlowGraph()
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="C", exit=True)
    g.add_edge(0, 1)
    g.add_edge(2, 1)
    with test.Raises(
            control_flow_graph.MalformedControlFlowGraphError) as e_ctx:
        g.ValidateControlFlowGraph()
    assert str(e_ctx.value) == ("No path from entry node 'A' to exit node 'C' "
                                "in function `cfg`")
    assert not g.IsValidControlFlowGraph()
Beispiel #16
0
def test_ControlFlowGraph_IsValidControlFlowGraph_invalid_degrees():
    """Test that a graph where two nodes could be fused is invalid."""
    g = control_flow_graph.ControlFlowGraph()
    # Graph:
    #
    #      A --> B --> C
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="C", exit=True)
    g.add_edge(0, 1)
    g.add_edge(1, 2)
    with test.Raises(control_flow_graph.InvalidNodeDegree) as e_ctx:
        g.ValidateControlFlowGraph()
    assert str(e_ctx.value) == "outdegree(A) = 1, indegree(B) = 1"
    assert not g.IsValidControlFlowGraph()
Beispiel #17
0
def test_ControlFlowGraph_IsValidControlFlowGraph_while_loop():
    """Test that a while loop graph is valid."""
    g = control_flow_graph.ControlFlowGraph()
    # Graph:
    #
    #     +--------+
    #     |        |
    #     v        |
    #     A+------>B       C
    #     |                ^
    #     |                |
    #     +----------------+
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="C", exit=True)
    g.add_edge(0, 1)
    g.add_edge(1, 0)
    g.add_edge(0, 2)
    assert g.ValidateControlFlowGraph() == g
    assert g.IsValidControlFlowGraph()
Beispiel #18
0
def test_ControlFlowGraph_exit_block():
    """Test exit block."""
    g = control_flow_graph.ControlFlowGraph()
    # Graph:
    #
    #     +----> B -----+
    #     |             |
    #     |             v
    #     A             D
    #     |             ^
    #     |             |
    #     +----> C -----+
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="C")
    g.add_node(3, name="D", exit=True)
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 3)
    g.add_edge(2, 3)
    assert g.exit_blocks == [3]
Beispiel #19
0
def test_ControlFlowGraph_IsValidControlFlowGraph_if_else_loop():
    """Test that an if-else loop graph is valid."""
    g = control_flow_graph.ControlFlowGraph()
    # Graph:
    #
    #     +----> B -----+
    #     |             |
    #     |             v
    #     A             D
    #     |             ^
    #     |             |
    #     +----> C -----+
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="C")
    g.add_node(3, name="D", exit=True)
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 3)
    g.add_edge(2, 3)
    assert g.ValidateControlFlowGraph() == g
    assert g.IsValidControlFlowGraph()
Beispiel #20
0
def test_ControlFlowGraph_IsValidControlFlowGraph_while_loop_with_exit():
    """Test that a while loop with an if branch exit is valid."""
    g = control_flow_graph.ControlFlowGraph()
    # Graph:
    #
    #     +----------------+
    #     |                |
    #     v                |
    #     A+------>B+----->C       D
    #     |        |               ^
    #     |        |               |
    #     +------->+---------------+
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="C")
    g.add_node(3, name="D", exit=True)
    g.add_edge(0, 1)
    g.add_edge(1, 2)
    g.add_edge(2, 0)
    g.add_edge(0, 3)
    g.add_edge(1, 3)
    assert g.ValidateControlFlowGraph() == g
    assert g.IsValidControlFlowGraph()
Beispiel #21
0
def test_ControlFlowGraph_IsValidControlFlowGraph_unamed_nodes():
    """Test that all nodes in a graph must have a name."""
    g = control_flow_graph.ControlFlowGraph()
    # Graph:
    #
    #     +----> B -----+
    #     |             |
    #     |             v
    #     A             D
    #     |             ^
    #     |             |
    #     +---->   -----+
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2)
    g.add_node(3, name="D", exit=True)
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 3)
    g.add_edge(2, 3)
    with test.Raises(control_flow_graph.MissingNodeName) as e_ctx:
        g.ValidateControlFlowGraph()
    assert str(e_ctx.value) == "Node 2 has no name in function `cfg`"
    assert not g.IsValidControlFlowGraph()
Beispiel #22
0
def test_ControlFlowGraph_IsValidControlFlowGraph_duplicate_names():
    """Test that duplicate names is an error."""
    g = control_flow_graph.ControlFlowGraph()
    # Graph:
    #
    #     +----> B -----+
    #     |             |
    #     |             v
    #     A             D
    #     |             ^
    #     |             |
    #     +----> B -----+
    g.add_node(0, name="A", entry=True)
    g.add_node(1, name="B")
    g.add_node(2, name="B")
    g.add_node(3, name="D", exit=True)
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 3)
    g.add_edge(2, 3)
    with test.Raises(control_flow_graph.DuplicateNodeName) as e_ctx:
        g.ValidateControlFlowGraph()
    assert str(e_ctx.value) == "Duplicate node name 'B' in function `cfg`"
    assert not g.IsValidControlFlowGraph()
Beispiel #23
0
def test_ControlFlowGraph_validate_one_node():
    """Test that single-node graph is valid."""
    g = control_flow_graph.ControlFlowGraph()
    g.add_node(0, name="A", entry=True, exit=True)
    g.ValidateControlFlowGraph()