def test_insert_node_above(): # above root t = Tree() t.insert_node(Node("initial_root")) t.insert_node(node=Node("new_root"), child_id="initial_root", key="between") assert t.root == "new_root" assert to_key_id(t.children("new_root")) == [("between", "initial_root")] tree_sanity_check(t) assert (t.show() == """{} └── between: {} """) # above node t = get_sample_tree() t.insert_node(Node("new"), child_id="aa0", key="to") assert "new" in t assert (t.show() == """{} ├── a: {} │ ├── a: [] │ │ ├── {} │ │ │ └── to: AA0 │ │ └── AA1 │ └── b: {} └── c: [] ├── C0 └── C1 """) tree_sanity_check(t)
def test_clone_with_tree(): t = get_sample_tree() # deep = False t_shallow_clone = t.clone(with_nodes=True) assert isinstance(t_shallow_clone, Tree) assert t_shallow_clone is not t assert not t_shallow_clone.is_empty() assert t_shallow_clone._nodes_map is not t._nodes_map assert t_shallow_clone._nodes_map == t._nodes_map assert t_shallow_clone._nodes_parent is not t._nodes_parent assert_default_dict_equal(t_shallow_clone._nodes_parent, t._nodes_parent) assert t_shallow_clone._nodes_children_list is not t._nodes_children_list assert_default_dict_equal(t_shallow_clone._nodes_children_list, t._nodes_children_list) # nodes are shallow copies for nid, node in t._nodes_map.items(): assert t_shallow_clone._nodes_map[nid] is node tree_sanity_check(t) tree_sanity_check(t_shallow_clone) # deep = True t_custom_deep_clone = t.clone(deep=True) for nid, node in t_custom_deep_clone._nodes_map.items(): assert t._nodes_map[nid] is not node
def test_drop_subtree(): t = get_sample_tree() key, a1_subtree = t.drop_subtree("aa") assert key == "a" assert isinstance(a1_subtree, Tree) assert sorted(to_key_id(a1_subtree.list()), key=itemgetter(1)) == sorted([(None, "aa"), (0, "aa0"), (1, "aa1")], key=itemgetter(1)) tree_sanity_check(t) tree_sanity_check(a1_subtree) assert sorted(to_key_id(t.list()), key=itemgetter(1)) == sorted( [ (None, "root"), ("a", "a"), ("b", "ab"), ("c", "c"), (0, "c0"), (1, "c1"), ], key=itemgetter(1), ) assert (t.show() == """{} ├── a: {} │ └── b: {} └── c: [] ├── C0 └── C1 """) assert (a1_subtree.show() == """[] ├── AA0 └── AA1 """)
def test_empty_clone(): t = get_sample_tree() # deep = False t_shallow_empty_clone = t.clone(with_nodes=False) assert isinstance(t_shallow_empty_clone, Tree) assert t_shallow_empty_clone is not t assert t_shallow_empty_clone.is_empty() tree_sanity_check(t) tree_sanity_check(t_shallow_empty_clone)
def test_insert_tree_below(): t = get_sample_tree() # insert subtree t_to_paste = get_sample_tree_2() t.insert(t_to_paste, parent_id="c") tree_sanity_check(t) tree_sanity_check(t_to_paste) assert (t.show() == """{} ├── a: {} │ ├── a: [] │ │ ├── AA0 │ │ └── AA1 │ └── b: {} └── c: [] ├── C0 ├── C1 └── [] ├── {} │ └── a: {} └── {} """) assert all(nid in t for nid in ("broot", "b1", "b1a", "b2")) # by default pasted new tree is a shallow copy k, n = t.get("broot") assert k == 2 k_ini, n_ini = t_to_paste.get("broot") assert k_ini is None assert n == n_ini # cannot repaste tree, because then there would be node duplicates with pytest.raises(DuplicatedNodeError): t.insert(t_to_paste, parent_id="aa0") tree_sanity_check(t) tree_sanity_check(t_to_paste)
def test_merge(): t = get_sample_tree() # merge under list t_to_merge = get_sample_tree_2() t.merge(new_tree=t_to_merge, nid="c") tree_sanity_check(t) tree_sanity_check(t_to_merge) assert (t.show() == """{} ├── a: {} │ ├── a: [] │ │ ├── AA0 │ │ └── AA1 │ └── b: {} └── c: [] ├── {} │ └── a: {} ├── {} ├── C0 └── C1 """) # new tree root is not conserved assert "broot" not in t assert all(nid in t for nid in ("b1", "b1a", "b2")) old_key, old_node = t_to_merge.get("b1") new_key, new_node = t.get("b1") assert old_key == new_key assert old_node is new_node # cannot remerge tree, because then there would be node duplicates with pytest.raises(DuplicatedNodeError): t.merge(new_tree=t_to_merge, nid="aa0") tree_sanity_check(t) tree_sanity_check(t_to_merge) # merge on initial empty tree t = Tree() t.merge(get_sample_tree_2()) tree_sanity_check(t) assert (t.show() == """[] ├── {} │ └── a: {} └── {} """) # in this case new_tree root is conserved since initial tree is empty assert all(nid in t for nid in ("broot", "b1", "b1a", "b2"))
def test_drop_node(): # drop with children t = get_sample_tree() node_key, aa_node = t.drop_node("aa") tree_sanity_check(t) assert node_key == "a" assert isinstance(aa_node, Node) assert aa_node.identifier == "aa" assert all(nid not in t for nid in ("aa", "aa0", "aa1")) assert (t.show() == """{} ├── a: {} │ └── b: {} └── c: [] ├── C0 └── C1 """) # drop without children (rebase children to dropped node's parent), possible because node and its parent are of # same type t2 = get_sample_tree() a_key, a_node = t2.drop_node("a", with_children=False) tree_sanity_check(t2) assert a_key == "a" assert isinstance(a_node, Node) assert all(nid in t2 for nid in ("aa", "ab", "aa0", "aa1")) assert "a" not in t2 assert (t2.show() == """{} ├── a: [] │ ├── AA0 │ └── AA1 ├── b: {} └── c: [] ├── C0 └── C1 """) # cannot drop root if it has multiple children t3 = get_sample_tree() with pytest.raises(MultipleRootError): t3.drop_node("root", with_children=False) # drop without children impossible if node type and parent node type are different (because list keys are ints, map keys are str) t4 = get_sample_tree() with pytest.raises(ValueError): t4.drop_node("aa", with_children=False)
def test_insert_tree_above(): t = get_sample_tree() # cannot insert subtree above if inserted tree has multiple leaves, and without specifying under which new tree # node existing children should be placed with pytest.raises(ValueError): t.insert_tree(get_sample_tree_2(), child_id="aa0") assert all(nid not in t for nid in {"broot", "b1", "b1a", "b2"}) tree_sanity_check(t) # insert subtree with proper specification t.insert_tree(get_sample_tree_2(), child_id="aa0", child_id_below="b2", key="new-key") tree_sanity_check(t) assert all(nid in t for nid in {"broot", "b1", "b1a", "b2"}) assert (t.show() == """{} ├── a: {} │ ├── a: [] │ │ ├── [] │ │ │ ├── {} │ │ │ │ └── a: {} │ │ │ └── {} │ │ │ └── new-key: AA0 │ │ └── AA1 │ └── b: {} └── c: [] ├── C0 └── C1 """) # insert subtree, without proper child specification, but with only one leaf will by default place children # below that leaf t = get_sample_tree() t2 = get_sample_tree_2() t2.drop_node("b2") t.insert_tree(t2, child_id="aa0", key="some_key") tree_sanity_check(t) tree_sanity_check(t2) assert (t.show() == """{} ├── a: {} │ ├── a: [] │ │ ├── [] │ │ │ └── {} │ │ │ └── a: {} │ │ │ └── some_key: AA0 │ │ └── AA1 │ └── b: {} └── c: [] ├── C0 └── C1 """)
def test_clone_with_subtree(): t = get_sample_tree() t_clone = t.clone(with_nodes=True, new_root="a") tree_sanity_check(t) tree_sanity_check(t_clone) assert isinstance(t_clone, Tree) assert t_clone is not t assert not t_clone.is_empty() assert set(t_clone._nodes_map.keys()) == {"a", "aa", "ab", "aa0", "aa1"} assert (t_clone.show() == """{} ├── a: [] │ ├── AA0 │ └── AA1 └── b: {} """) # nodes are shallow copies for _, node in t_clone.list(): assert node is t.get(node.identifier)[1]
def test_insert_root(): t = Tree() root_node = Node(identifier="a") t.insert_node(root_node) assert to_key_id(t.list()) == [(None, "a")] t._nodes_map["a"] is root_node assert t._nodes_parent["a"] is None assert t._nodes_children_list["a"] == [] assert t._nodes_children_map["a"] == {} tree_sanity_check(t) # cannot add second root with pytest.raises(MultipleRootError): t.insert_node(Node(identifier="b")) assert to_key_id(t.list()) == [(None, "a")] tree_sanity_check(t) # wrong node insertion with pytest.raises(AttributeError): Tree().insert_node({"key": "a"})
def test_insert_tree_at_root(): t = Tree() t.insert_tree(get_sample_tree()) tree_sanity_check(t) assert (t.show() == """{} ├── a: {} │ ├── a: [] │ │ ├── AA0 │ │ └── AA1 │ └── b: {} └── c: [] ├── C0 └── C1 """) # cannot insert at root if already present root t = Tree() t.insert_node(Node("present_root")) with pytest.raises(MultipleRootError): t.insert_tree(get_sample_tree()) tree_sanity_check(t)
def test_insert_node_below(): t = Tree() t.insert_node(Node("root_id")) # cannot insert under not existing parent with pytest.raises(NotFoundNodeError): t.insert_node(Node(identifier="a"), parent_id="what") tree_sanity_check(t) # insert node below another one node_a = Node("a_id") t.insert_node(node_a, parent_id="root_id", key="a") assert set(t._nodes_map.keys()) == {"root_id", "a_id"} assert t._nodes_map["a_id"] == node_a assert t._nodes_parent["root_id"] is None assert t._nodes_parent["a_id"] == "root_id" assert t._nodes_children_list["a_id"] == [] assert t._nodes_children_map["root_id"] == {"a_id": "a"} tree_sanity_check(t) # try to insert node with same id than existing node with pytest.raises(DuplicatedNodeError): t.insert_node(Node("a_id"), parent_id="root_id", key="b") tree_sanity_check(t)