def tree_a():
    a = Label("a")
    a_a = Label("a_a", parent=a)

    a_a_a = Label("a_a_a", parent=a_a)

    a_a_b = Label("a_a_b", parent=a_a)
    a_a_b_a = Label("a_a_b_a", parent=a_a_b)
    a_a_b_b = Label("a_a_b_b", parent=a_a_b)

    a_a_c = Label("a_a_c", parent=a_a)
    a_a_c_a = Label("a_a_c_a")
    a_a_c_b_a = Label("a_a_c_b_a")
    a_a_c_b = Label("a_a_c_b", children=(a_a_c_b_a, ))
    a_a_c_a_a = Label("a_a_c_a_a")
    a_a_c_a_b = Label("a_a_c_a_b")
    a_a_c_a_b_a = Label("a_a_c_a_b_a", parent=a_a_c_a_b)

    a_a_c.add(a_a_c_a, a_a_c_b)
    a_a_c_a_a.attach(a_a_c_a)
    a_a_c_a_b.attach(a_a_c_a)

    a_b = Label("a_b", parent=a)
    a_b_a = Label("a_b_a", parent=a_b)
    a_b_a_a = Label("a_b_a_a", parent=a_b_a)
    a_b_a_b = Label("a_b_a_b", parent=a_b_a)

    return a
    def test_clade(self):
        a = Label("a")
        a_a = Label("a_a", parent=a)

        a_a_a = Label("a_a_a", parent=a_a)

        a_a_b = Label("a_a_b", parent=a_a)
        a_a_b_a = Label("a_a_b_a", parent=a_a_b)
        a_a_b_b = Label("a_a_b_b", parent=a_a_b)

        a_a_c = Label("a_a_c", parent=a_a)
        a_a_c_a = Label("a_a_c_a")
        a_a_c_b_a = Label("a_a_c_b_a")
        a_a_c_b = Label("a_a_c_b", children=(a_a_c_b_a, ))
        a_a_c_a_a = Label("a_a_c_a_a")
        a_a_c_a_b = Label("a_a_c_a_b")
        a_a_c_a_b_a = Label("a_a_c_a_b_a", parent=a_a_c_a_b)

        a_a_c.add(a_a_c_a, a_a_c_b)
        a_a_c_a_a.attach(a_a_c_a)
        a_a_c_a_b.attach(a_a_c_a)

        a_b = Label("a_b", parent=a)
        a_b_a = Label("a_b_a", parent=a_b)
        a_b_a_a = Label("a_b_a_a", parent=a_b_a)
        a_b_a_b = Label("a_b_a_b", parent=a_b_a)

        assert a_a_c_b.clade(a_a_c_a_b_a) == Tree(a_a_c)
        assert a_a_c_a_b_a.clade(a_a_c_b) == Tree(a_a_c)

        assert a_a_c_a_b_a.clade(a_a_b_a) == Tree(a_a)
        assert a_a_b_a.clade(a_a_c_a_b_a) == Tree(a_a)

        assert a_a.clade(a_a) == Tree(a_a)

        for label_name in a_a.descendants:
            assert a_a.clade(a_a.descendants[label_name]) == Tree(a_a)
    def test_last_common_ancestor(self):
        a = Label("a")
        a_a = Label("a_a", parent=a)

        a_a_a = Label("a_a_a", parent=a_a)

        a_a_b = Label("a_a_b", parent=a_a)
        a_a_b_a = Label("a_a_b_a", parent=a_a_b)
        a_a_b_b = Label("a_a_b_b", parent=a_a_b)

        a_a_c = Label("a_a_c", parent=a_a)
        a_a_c_a = Label("a_a_c_a")
        a_a_c_b_a = Label("a_a_c_b_a")
        a_a_c_b = Label("a_a_c_b", children=(a_a_c_b_a, ))
        a_a_c_a_a = Label("a_a_c_a_a")
        a_a_c_a_b = Label("a_a_c_a_b")
        a_a_c_a_b_a = Label("a_a_c_a_b_a", parent=a_a_c_a_b)

        a_a_c.add(a_a_c_a, a_a_c_b)
        a_a_c_a_a.attach(a_a_c_a)
        a_a_c_a_b.attach(a_a_c_a)

        a_b = Label("a_b", parent=a)
        a_b_a = Label("a_b_a", parent=a_b)
        a_b_a_a = Label("a_b_a_a", parent=a_b_a)
        a_b_a_b = Label("a_b_a_b", parent=a_b_a)

        assert a_a_c_b.last_common_ancestor(a_a_c_a_b_a) == a_a_c
        assert a_a_c_a_b_a.last_common_ancestor(a_a_c_b) == a_a_c

        assert a_a_c_a_b_a.last_common_ancestor(a_a_b_a) == a_a
        assert a_a_b_a.last_common_ancestor(a_a_c_a_b_a) == a_a

        assert a_a.last_common_ancestor(a_a) == a_a

        for label_name in a_a.descendants:
            assert a_a.last_common_ancestor(a_a.descendants[label_name]) == a_a
    def test_attach_add_detach(self):
        label_a = Label('label_a')
        label_b = Label('label_b')
        label_c = Label('label_c', some_property='some_value')

        fake_label_a = Label('label_a')

        # Generic link testing
        label_a.attach(label_b)
        self._test_label_link(label_b, label_a)

        # More exact testing here
        assert label_a.depth == 1
        assert label_a.ancestors == (label_b, )
        assert label_b.descendants == {'label_a': label_a}

        # Not fake attach created ?
        assert label_b.parent is None
        assert not label_b.ancestors
        assert label_b.depth == 0
        assert not label_a.children
        assert not label_a.descendants

        # Assert label_c was a simple witness
        self._test_label_no_link(label_c, label_a)
        self._test_label_no_link(label_c, label_b)

        # Add another node
        label_a.add(label_c)
        self._test_label_link(label_a, label_c)

        # More exact testing here
        assert label_a.ancestors == (label_b, )
        assert label_c.ancestors == (label_a, label_b)
        assert label_a.descendants == {'label_c': label_c}
        assert label_b.descendants == {'label_a': label_a, 'label_c': label_c}

        # Not fake attach created ?
        assert label_b.parent is None
        assert not label_b.ancestors
        assert not label_c.children
        assert not label_c.descendants

        # Test name duplicate sanity checks
        with pytest.raises(ValueError,
                           match=r'Invalid tree: Overlapping tree '
                           r'(?:{|set\(\[)\'label_a\'[}\])]+ found in'):
            fake_label_a.add(label_b)

        # Test name duplicate sanity checks
        with pytest.raises(ValueError,
                           match=r'Invalid tree: Overlapping tree '
                           r'(?:{|set\(\[)\'label_a\'[}\])]+ found in'):
            fake_label_a.attach(label_c)

        # Test name duplicate sanity checks
        with pytest.raises(ValueError,
                           match=r'Invalid tree: Overlapping tree '
                           r'(?:{|set\(\[)\'label_a\'[}\])]+ found in'):
            label_c.add(fake_label_a)

        # Test name duplicate sanity checks
        with pytest.raises(ValueError,
                           match=r'Invalid tree: Overlapping tree '
                           r'(?:{|set\(\[)\'label_a\'[}\])]+ found in'):
            fake_label_a.add(label_c)

        # Test name duplicate sanity checks
        with pytest.raises(
                ValueError,
                match=
                r'Invalid tree: adding label_a to label_a\'s tree is impossible.'
        ):
            label_a.add(fake_label_a)

        # Test name duplicate sanity checks
        with pytest.raises(
                ValueError,
                match=
                r'Invalid tree: adding label_a to label_a\'s tree is impossible.'
        ):
            label_a.attach(fake_label_a)

        # Test name duplicate sanity checks
        with pytest.raises(
                ValueError,
                match=
                r'Invalid tree: adding label_a to label_a\'s tree is impossible.'
        ):
            fake_label_a.add(label_a)

        # Test name duplicate sanity checks
        with pytest.raises(
                ValueError,
                match=
                r'Invalid tree: adding label_a to label_a\'s tree is impossible.'
        ):
            fake_label_a.attach(label_a)

        # Test name collision is inefficient for add or attach
        label_b.add(fake_label_a)
        assert label_a.id in set([label.id for label in label_b.children])
        assert fake_label_a.id not in set(
            [label.id for label in label_b.children])

        label_c.attach(fake_label_a)
        assert label_c.parent.id != fake_label_a.id
        assert label_c.parent.id == label_a.id

        fake_label_a.attach(label_b)
        assert label_a.id in set([label.id for label in label_b.children])
        assert fake_label_a.id not in set(
            [label.id for label in label_b.children])

        # Remove the a -> b link upward
        label_a.detach(label_b)
        self._test_label_no_link(label_a, label_b)
        self._test_label_link(label_a, label_c)

        assert label_a.parent is None
        assert not label_a.ancestors
        assert label_a.depth == 0
        assert not label_b.children
        assert not label_b.descendants

        # Remove the c -> a link downward
        label_a.detach(label_c)
        self._test_label_no_link(label_a, label_c)

        assert label_c.parent is None
        assert not label_c.ancestors
        assert label_c.depth == 0
        assert not label_a.children
        assert not label_a.descendants

        # Test silent ignore of dubious detach
        label_a.detach(label_c, label_b)

        # Test properties
        label_a.parent = label_b
        self._test_label_link(label_b, label_a)

        # More exact testing here
        assert label_a.depth == 1
        assert label_a.ancestors == (label_b, )
        assert label_b.descendants == {'label_a': label_a}

        # Test properties
        label_a.parent = label_c
        self._test_label_no_link(label_a, label_b)
        self._test_label_link(label_c, label_a)

        # More exact testing here
        assert label_a.depth == 1
        assert label_a.ancestors == (label_c, )
        assert label_c.descendants == {'label_a': label_a}

        label_c.detach(label_a)
        # Test properties
        label_a.children = (label_b, )
        self._test_label_link(label_a, label_b)

        # More exact testing here
        assert label_b.depth == 1
        assert label_b.ancestors == (label_a, )
        assert label_a.descendants == {'label_b': label_b}

        # Test properties
        label_a.children = (label_c, )
        self._test_label_no_link(label_a, label_b)
        self._test_label_link(label_a, label_c)

        # More exact testing here
        assert label_c.depth == 1
        assert label_c.ancestors == (label_a, )
        assert label_a.descendants == {'label_c': label_c}

        # Test constructor
        label_d = Label('label_d', parent=label_a)
        self._test_label_link(label_a, label_c)
        self._test_label_link(label_a, label_d)

        # More exact testing here
        assert label_d.depth == 1
        assert label_d.ancestors == (label_a, )
        assert label_a.descendants == {'label_c': label_c, 'label_d': label_d}

        label_e = Label('label_e', children=(label_a, label_b))
        self._test_label_link(label_e, label_b)
        self._test_label_link(label_e, label_a)
        self._test_label_link(label_a, label_c)
        self._test_label_link(label_a, label_d)

        # More exact testing here
        assert label_b.depth == 1
        assert label_b.ancestors == (label_e, )
        assert label_d.depth == 2
        assert label_d.ancestors == (label_a, label_e)
        assert label_e.descendants == {
            'label_a': label_a,
            'label_b': label_b,
            'label_c': label_c,
            'label_d': label_d
        }