blob: a547cb6c72de7c7a57502c98697c4eaedc314a09 [file] [log] [blame]
def test_descendants():
g = new_graph()
def node(name):
k = g.key("node", name)
g.add_node(k, idempotent = True)
return k
def edge(parent, child):
g.add_edge(node(parent), node(child))
root = node("root")
edge("root", "3")
edge("root", "2")
edge("root", "1")
edge("1", "1_1")
edge("1_1", "leaf")
edge("2", "leaf")
g.finalize()
# Redefine 'node' to return graph.node now, to make assertions below look
# less cluttered.
def node(name):
return g.node(g.key("node", name))
# Works without visitor callback: just returns all descendants.
# In 'key' order, breadth first (default).
assert.eq(g.descendants(root), [
node("root"),
node("1"),
node("2"),
node("3"),
node("1_1"),
node("leaf"),
])
# In reverse 'key' order, breadth first.
assert.eq(g.descendants(root, order_by = "~key"), [
node("root"),
node("3"),
node("2"),
node("1"),
node("leaf"),
node("1_1"),
])
# In 'def' order, breadth first.
assert.eq(g.descendants(root, order_by = "def"), [
node("root"),
node("3"),
node("2"),
node("1"),
node("leaf"),
node("1_1"),
])
# In reverse 'def' order, breadth first.
assert.eq(g.descendants(root, order_by = "~def"), [
node("root"),
node("1"),
node("2"),
node("3"),
node("1_1"),
node("leaf"),
])
# In 'key' order, depth first.
assert.eq(g.descendants(root, topology = "depth"), [
node("leaf"),
node("1_1"),
node("1"),
node("2"),
node("3"),
node("root"),
])
# In reverse 'key' order, depth first.
assert.eq(g.descendants(root, order_by = "~key", topology = "depth"), [
node("3"),
node("leaf"),
node("2"),
node("1_1"),
node("1"),
node("root"),
])
# In 'def' order, depth first.
assert.eq(g.descendants(root, order_by = "def", topology = "depth"), [
node("3"),
node("leaf"),
node("2"),
node("1_1"),
node("1"),
node("root"),
])
# In reverse 'def' order, depth first.
assert.eq(g.descendants(root, order_by = "~def", topology = "depth"), [
node("leaf"),
node("1_1"),
node("1"),
node("2"),
node("3"),
node("root"),
])
# Just visit everything and see what we get in each individual call.
# In 'key' order (default).
visited = []
def visitor(node, children):
visited.append((node, children))
return children
g.descendants(root, visitor)
assert.eq(visited, [
(node("root"), [node("1"), node("2"), node("3")]),
(node("1"), [node("1_1")]),
(node("2"), [node("leaf")]),
(node("3"), []),
(node("1_1"), [node("leaf")]),
(node("leaf"), []), # visited only once
])
# In 'def' order.
visited = []
def visitor(node, children):
visited.append((node, children))
return children
g.descendants(root, visitor, "def")
assert.eq(visited, [
(node("root"), [node("3"), node("2"), node("1")]),
(node("3"), []),
(node("2"), [node("leaf")]),
(node("1"), [node("1_1")]),
(node("leaf"), []), # visited only once
(node("1_1"), [node("leaf")]),
])
# Verify we can select what to visit.
visited = []
def visitor(node, children):
visited.append((node, children))
return [children[0]] if children else []
assert.eq(g.descendants(root, visitor), [
node("root"),
node("1"),
node("1_1"),
node("leaf"),
])
assert.eq(visited, [
(node("root"), [node("1"), node("2"), node("3")]),
(node("1"), [node("1_1")]),
(node("1_1"), [node("leaf")]),
(node("leaf"), []),
])
# Checks the type of the return value, allows only subset of 'children'.
def visitor(node, children):
return "huh"
assert.fails(
lambda: g.descendants(root, visitor),
"unexpectedly returned string instead of a list",
)
def visitor(node, children):
return children + ["huh"]
assert.fails(
lambda: g.descendants(root, visitor),
"unexpectedly returned string as element #3 instead of a graph.node",
)
def visitor(node, children):
return [node]
assert.fails(
lambda: g.descendants(root, visitor),
r'unexpectedly returned node\("root"\) which is not a child of node\("root"\)',
)
test_descendants()