def MergeChildren(node_a: ActionNode, node_b: ActionNode) -> None: assert not node_a.dead assert not node_b.dead assert node_a.action.name is not node_b.action.name node_a.AssertValidity() node_b.AssertValidity() node_a_name = node_a.action.name node_b_name = node_b.action.name children_a = list(node_a.children.copy().values()) children_b = list(node_b.children.copy().values()) for child in children_a + children_b: child = child.ResolveToAliveNode() child.AssertValidity() child_name = child.action.name if (child_name in node_a.children and child_name in node_b.children): MergeNodes(node_a.children[child_name], node_b.children[child_name]) elif child_name in node_a.children: if (node_b_name in child.parents): node_b = MergeNodes(node_b, child.parents[node_b_name]) else: node_b.AddChild(child) elif child_name in node_b.children: if (node_a_name in child.parents): node_a = MergeNodes(node_a, child.parents[node_a_name]) else: node_a.AddChild(child) else: assert False node_a = node_a.ResolveToAliveNode() node_b = node_b.ResolveToAliveNode() resolved_children = ({ k: node_a.children.get(k).ResolveToAliveNode() for k in node_a.children.keys() }) node_a.children = resolved_children.copy() node_b.children = resolved_children merged_state_check_coverage = MergeStateCheckCoverage( node_a.state_check_actions_coverage, node_b.state_check_actions_coverage) node_a.state_check_actions.update(node_b.state_check_actions) node_a.state_check_actions_coverage = merged_state_check_coverage node_b.state_check_actions.update(node_a.state_check_actions) node_b.state_check_actions_coverage = merged_state_check_coverage.copy( ) node_a.AssertValidity() node_b.AssertValidity()
def AddActionListToGraph(parent: ActionNode, current: ActionNode, action_list: List[Action], end: ActionNode, partial_tests: Set[CoverageTest]) -> None: nonlocal root_node assert isinstance(parent, ActionNode) assert isinstance(end, ActionNode) assert len(action_list) > 0 only_state_check_actions = True current.AssertValidity() end.AssertValidity() for action in action_list: assert isinstance(action, Action) if action.is_state_check: parent.AddStateCheckAction(action, ActionCoverage.PARTIAL) parent.partial_coverage_tests.update(partial_tests) continue only_state_check_actions = False if action.name in parent.children: current = parent.children[action.name] else: current = ActionNode(action) current.coverage = ActionCoverage.PARTIAL parent.AddChild(current) current.partial_coverage_tests.update(partial_tests) parent = current if current == end: return if only_state_check_actions: # If only state_check actions were added, then no need to add a new # edge. return logging.info("Merging children of\n{" + parent.GetGraphPathStr() + "}\n{" + end.GetGraphPathStr() + "}") if current.action.name is end.action.name: MergeNodes(current, end) else: MergeChildren(current, end) root_node.AssertChildrenValidity()
def MergeNodes(node_a: ActionNode, node_b: ActionNode) -> ActionNode: assert not node_a.dead assert not node_b.dead if node_a == node_b: return node_a assert node_a.action.name == node_b.action.name logging.info("Merging nodes with paths:\n{" + node_a.GetGraphPathStr() + "},\n{" + node_b.GetGraphPathStr() + "}") new_node = ActionNode(node_a.action) new_node.coverage = (ActionCoverage.FULL if node_a.coverage == ActionCoverage.FULL or node_b.coverage == ActionCoverage.FULL else ActionCoverage.PARTIAL) new_node.state_check_actions = node_a.state_check_actions new_node.state_check_actions.update(node_b.state_check_actions) new_node.state_check_actions_coverage = MergeStateCheckCoverage( node_a.state_check_actions_coverage, node_b.state_check_actions_coverage) new_node.full_coverage_tests = node_a.full_coverage_tests new_node.full_coverage_tests.update(node_b.full_coverage_tests) new_node.partial_coverage_tests = node_a.partial_coverage_tests new_node.partial_coverage_tests.update(node_b.partial_coverage_tests) children_a = node_a.children.copy() children_b = node_b.children.copy() parents_a = node_a.parents.copy() parents_b = node_b.parents.copy() # Fully remove the merging nodes from the graph for child in list(children_a.values()) + list(children_b.values()): if new_node.action.name in child.parents: del child.parents[new_node.action.name] for parent in list(parents_a.values()) + list(parents_b.values()): if new_node.action.name in parent.children: del parent.children[new_node.action.name] # Merge children. # Start by adding the non-intersecting children to the dictionary. children = ({ k: children_a.get(k, children_b.get(k)).ResolveToAliveNode() for k in (children_a.keys() ^ children_b.keys()) }) # For all children that are the same, they must be merged. children.update({ k: MergeNodes(children_a[k].ResolveToAliveNode(), children_b[k].ResolveToAliveNode()) for k in (children_a.keys() & children_b.keys()) }) # Merge parents. # Start by adding the non-intersecting parents to the dictionary. parents = ({ k: parents_a.get(k, parents_b.get(k)).ResolveToAliveNode() for k in (parents_a.keys() ^ parents_b.keys()) }) # For all parents that are the same, they must be merged. parents.update({ k: MergeNodes(parents_a[k].ResolveToAliveNode(), parents_b[k].ResolveToAliveNode()) for k in (parents_a.keys() & parents_b.keys()) }) # Re-add the node back into the graph. for child in children.values(): child = child.ResolveToAliveNode() new_node.AddChild(child) for parent in parents.values(): parent = parent.ResolveToAliveNode() parent.AddChild(new_node) node_a.dead = new_node node_b.dead = new_node new_node.AssertValidity() return new_node