// Test case for // - nextSkippingChildren // - previousSkippingChildren TEST_F(ComposedTreeTraversalTest, nextSkippingChildren) { const char* mainHTML = "<div id='m0'>m0</div>" "<div id='m1'>" "<span id='m10'>m10</span>" "<span id='m11'>m11</span>" "</div>" "<div id='m2'>m2</div>"; const char* shadowHTML = "<content select='#m11'></content>" "<a id='s11'>s11</a>" "<a id='s12'>" "<b id='s120'>s120</b>" "<content select='#m10'></content>" "</a>"; setupSampleHTML(mainHTML, shadowHTML, 1); RefPtrWillBeRawPtr<Element> body = document().body(); RefPtrWillBeRawPtr<Element> m0 = body->querySelector("#m0", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m1 = body->querySelector("#m1", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m2 = body->querySelector("#m2", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m10 = body->querySelector("#m10", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m11 = body->querySelector("#m11", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = m1->openShadowRoot(); RefPtrWillBeRawPtr<Element> s11 = shadowRoot->querySelector("#s11", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> s12 = shadowRoot->querySelector("#s12", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> s120 = shadowRoot->querySelector("#s120", ASSERT_NO_EXCEPTION); // Main tree node to main tree node EXPECT_EQ(*m1, ComposedTreeTraversal::nextSkippingChildren(*m0)); EXPECT_EQ(*m0, ComposedTreeTraversal::previousSkippingChildren(*m1)); // Distribute node to main tree node EXPECT_EQ(*m2, ComposedTreeTraversal::nextSkippingChildren(*m10)); EXPECT_EQ(*m1, ComposedTreeTraversal::previousSkippingChildren(*m2)); // Distribute node to node in shadow tree EXPECT_EQ(*s11, ComposedTreeTraversal::nextSkippingChildren(*m11)); EXPECT_EQ(*m11, ComposedTreeTraversal::previousSkippingChildren(*s11)); // Node in shadow tree to distributed node EXPECT_EQ(*s11, ComposedTreeTraversal::nextSkippingChildren(*m11)); EXPECT_EQ(*m11, ComposedTreeTraversal::previousSkippingChildren(*s11)); EXPECT_EQ(*m10, ComposedTreeTraversal::nextSkippingChildren(*s120)); EXPECT_EQ(*s120, ComposedTreeTraversal::previousSkippingChildren(*m10)); // Node in shadow tree to main tree EXPECT_EQ(*m2, ComposedTreeTraversal::nextSkippingChildren(*s12)); EXPECT_EQ(*m1, ComposedTreeTraversal::previousSkippingChildren(*m2)); }
// Test case for // - childAt // - countChildren // - hasChildren // - index // - isDescendantOf TEST_F(FlatTreeTraversalTest, childAt) { const char* mainHTML = "<div id='m0'>" "<span id='m00'>m00</span>" "<span id='m01'>m01</span>" "</div>"; const char* shadowHTML = "<a id='s00'>s00</a>" "<content select='#m01'></content>" "<a id='s02'>s02</a>" "<a id='s03'><content select='#m00'></content></a>" "<a id='s04'>s04</a>"; setupSampleHTML(mainHTML, shadowHTML, 0); Element* body = document().body(); Element* m0 = body->querySelector("#m0"); Element* m00 = m0->querySelector("#m00"); Element* m01 = m0->querySelector("#m01"); Element* shadowHost = m0; ShadowRoot* shadowRoot = shadowHost->openShadowRoot(); Element* s00 = shadowRoot->querySelector("#s00"); Element* s02 = shadowRoot->querySelector("#s02"); Element* s03 = shadowRoot->querySelector("#s03"); Element* s04 = shadowRoot->querySelector("#s04"); const unsigned numberOfChildNodes = 5; Node* expectedChildNodes[5] = {s00, m01, s02, s03, s04}; ASSERT_EQ(numberOfChildNodes, FlatTreeTraversal::countChildren(*shadowHost)); EXPECT_TRUE(FlatTreeTraversal::hasChildren(*shadowHost)); for (unsigned index = 0; index < numberOfChildNodes; ++index) { Node* child = FlatTreeTraversal::childAt(*shadowHost, index); EXPECT_EQ(expectedChildNodes[index], child) << "FlatTreeTraversal::childAt(*shadowHost, " << index << ")"; EXPECT_EQ(index, FlatTreeTraversal::index(*child)) << "FlatTreeTraversal::index(FlatTreeTraversal(*shadowHost, " << index << "))"; EXPECT_TRUE(FlatTreeTraversal::isDescendantOf(*child, *shadowHost)) << "FlatTreeTraversal::isDescendantOf(*FlatTreeTraversal(*shadowHost, " << index << "), *shadowHost)"; } EXPECT_EQ(nullptr, FlatTreeTraversal::childAt(*shadowHost, numberOfChildNodes + 1)) << "Out of bounds childAt() returns nullptr."; // Distribute node |m00| is child of node in shadow tree |s03|. EXPECT_EQ(m00, FlatTreeTraversal::childAt(*s03, 0)); }
TEST_F(FlatTreeTraversalTest, previousPostOrder) { const char* mainHTML = "<div id='m0'>m0</div>" "<div id='m1'>" "<span id='m10'>m10</span>" "<span id='m11'>m11</span>" "</div>" "<div id='m2'>m2</div>"; const char* shadowHTML = "<content select='#m11'></content>" "<a id='s11'>s11</a>" "<a id='s12'>" "<b id='s120'>s120</b>" "<content select='#m10'></content>" "</a>"; setupSampleHTML(mainHTML, shadowHTML, 1); Element* body = document().body(); Element* m0 = body->querySelector("#m0"); Element* m1 = body->querySelector("#m1"); Element* m2 = body->querySelector("#m2"); Element* m10 = body->querySelector("#m10"); Element* m11 = body->querySelector("#m11"); ShadowRoot* shadowRoot = m1->openShadowRoot(); Element* s11 = shadowRoot->querySelector("#s11"); Element* s12 = shadowRoot->querySelector("#s12"); Element* s120 = shadowRoot->querySelector("#s120"); EXPECT_EQ(*m0->firstChild(), FlatTreeTraversal::previousPostOrder(*m0)); EXPECT_EQ(*s12, FlatTreeTraversal::previousPostOrder(*m1)); EXPECT_EQ(*m10->firstChild(), FlatTreeTraversal::previousPostOrder(*m10)); EXPECT_EQ(*s120, FlatTreeTraversal::previousPostOrder(*m10->firstChild())); EXPECT_EQ(*s120, FlatTreeTraversal::previousPostOrder(*m10->firstChild(), s12)); EXPECT_EQ(*m11->firstChild(), FlatTreeTraversal::previousPostOrder(*m11)); EXPECT_EQ(*m0, FlatTreeTraversal::previousPostOrder(*m11->firstChild())); EXPECT_EQ(nullptr, FlatTreeTraversal::previousPostOrder(*m11->firstChild(), m11)); EXPECT_EQ(*m2->firstChild(), FlatTreeTraversal::previousPostOrder(*m2)); EXPECT_EQ(*s11->firstChild(), FlatTreeTraversal::previousPostOrder(*s11)); EXPECT_EQ(*m10, FlatTreeTraversal::previousPostOrder(*s12)); EXPECT_EQ(*s120->firstChild(), FlatTreeTraversal::previousPostOrder(*s120)); EXPECT_EQ(*s11, FlatTreeTraversal::previousPostOrder(*s120->firstChild())); EXPECT_EQ(nullptr, FlatTreeTraversal::previousPostOrder(*s120->firstChild(), s12)); }
// Test case for // - childAt // - countChildren // - hasChildren // - index // - isDescendantOf TEST_F(ComposedTreeTraversalTest, childAt) { const char* mainHTML = "<div id='m0'>" "<span id='m00'>m00</span>" "<span id='m01'>m01</span>" "</div>"; const char* shadowHTML = "<a id='s00'>s00</a>" "<content select='#m01'></content>" "<a id='s02'>s02</a>" "<a id='s03'><content select='#m00'></content></a>" "<a id='s04'>s04</a>"; setupSampleHTML(mainHTML, shadowHTML, 0); RefPtrWillBeRawPtr<Element> body = document().body(); RefPtrWillBeRawPtr<Element> m0 = body->querySelector("#m0", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m00 = m0->querySelector("#m00", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m01 = m0->querySelector("#m01", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> shadowHost = m0; RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = shadowHost->openShadowRoot(); RefPtrWillBeRawPtr<Element> s00 = shadowRoot->querySelector("#s00", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> s02 = shadowRoot->querySelector("#s02", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> s03 = shadowRoot->querySelector("#s03", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> s04 = shadowRoot->querySelector("#s04", ASSERT_NO_EXCEPTION); const unsigned numberOfChildNodes = 5; Node* expectedChildNodes[5] = { s00.get(), m01.get(), s02.get(), s03.get(), s04.get() }; ASSERT_EQ(numberOfChildNodes, ComposedTreeTraversal::countChildren(*shadowHost)); EXPECT_TRUE(ComposedTreeTraversal::hasChildren(*shadowHost)); for (unsigned index = 0; index < numberOfChildNodes; ++index) { Node* child = ComposedTreeTraversal::childAt(*shadowHost, index); EXPECT_EQ(expectedChildNodes[index], child) << "ComposedTreeTraversal::childAt(*shadowHost, " << index << ")"; EXPECT_EQ(index, ComposedTreeTraversal::index(*child)) << "ComposedTreeTraversal::index(ComposedTreeTraversal(*shadowHost, " << index << "))"; EXPECT_TRUE(ComposedTreeTraversal::isDescendantOf(*child, *shadowHost)) << "ComposedTreeTraversal::isDescendantOf(*ComposedTreeTraversal(*shadowHost, " << index << "), *shadowHost)"; } EXPECT_EQ(nullptr, ComposedTreeTraversal::childAt(*shadowHost, numberOfChildNodes + 1)) << "Out of bounds childAt() returns nullptr."; // Distribute node |m00| is child of node in shadow tree |s03|. EXPECT_EQ(m00.get(), ComposedTreeTraversal::childAt(*s03, 0)); }
TEST_F(ComposedTreeTraversalTest, previousPostOrder) { const char* mainHTML = "<div id='m0'>m0</div>" "<div id='m1'>" "<span id='m10'>m10</span>" "<span id='m11'>m11</span>" "</div>" "<div id='m2'>m2</div>"; const char* shadowHTML = "<content select='#m11'></content>" "<a id='s11'>s11</a>" "<a id='s12'>" "<b id='s120'>s120</b>" "<content select='#m10'></content>" "</a>"; setupSampleHTML(mainHTML, shadowHTML, 1); RefPtrWillBeRawPtr<Element> body = document().body(); RefPtrWillBeRawPtr<Element> m0 = body->querySelector("#m0", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m1 = body->querySelector("#m1", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m2 = body->querySelector("#m2", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m10 = body->querySelector("#m10", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m11 = body->querySelector("#m11", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = m1->openShadowRoot(); RefPtrWillBeRawPtr<Element> s11 = shadowRoot->querySelector("#s11", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> s12 = shadowRoot->querySelector("#s12", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> s120 = shadowRoot->querySelector("#s120", ASSERT_NO_EXCEPTION); EXPECT_EQ(*m0->firstChild(), ComposedTreeTraversal::previousPostOrder(*m0)); EXPECT_EQ(*s12, ComposedTreeTraversal::previousPostOrder(*m1)); EXPECT_EQ(*m10->firstChild(), ComposedTreeTraversal::previousPostOrder(*m10)); EXPECT_EQ(*s120, ComposedTreeTraversal::previousPostOrder(*m10->firstChild())); EXPECT_EQ(*s120, ComposedTreeTraversal::previousPostOrder(*m10->firstChild(), s12.get())); EXPECT_EQ(*m11->firstChild(), ComposedTreeTraversal::previousPostOrder(*m11)); EXPECT_EQ(*m0, ComposedTreeTraversal::previousPostOrder(*m11->firstChild())); EXPECT_EQ(nullptr, ComposedTreeTraversal::previousPostOrder(*m11->firstChild(), m11.get())); EXPECT_EQ(*m2->firstChild(), ComposedTreeTraversal::previousPostOrder(*m2)); EXPECT_EQ(*s11->firstChild(), ComposedTreeTraversal::previousPostOrder(*s11)); EXPECT_EQ(*m10, ComposedTreeTraversal::previousPostOrder(*s12)); EXPECT_EQ(*s120->firstChild(), ComposedTreeTraversal::previousPostOrder(*s120)); EXPECT_EQ(*s11, ComposedTreeTraversal::previousPostOrder(*s120->firstChild())); EXPECT_EQ(nullptr, ComposedTreeTraversal::previousPostOrder(*s120->firstChild(), s12.get())); }
TEST_F(FlatTreeTraversalTest, nextSiblingNotInDocumentFlatTree) { const char* mainHTML = "<div id='m0'>m0</div>" "<div id='m1'>" "<span id='m10'>m10</span>" "<span id='m11'>m11</span>" "</div>" "<div id='m2'>m2</div>"; const char* shadowHTML = "<content select='#m11'></content>"; setupSampleHTML(mainHTML, shadowHTML, 1); Element* body = document().body(); Element* m10 = body->querySelector("#m10"); EXPECT_EQ(nullptr, FlatTreeTraversal::nextSibling(*m10)); EXPECT_EQ(nullptr, FlatTreeTraversal::previousSibling(*m10)); }
// Test case for // - lastWithin // - lastWithinOrSelf TEST_F(ComposedTreeTraversalTest, lastWithin) { const char* mainHTML = "<div id='m0'>m0</div>" "<div id='m1'>" "<span id='m10'>m10</span>" "<span id='m11'>m11</span>" "<span id='m12'>m12</span>" // #m12 is not distributed. "</div>" "<div id='m2'></div>"; const char* shadowHTML = "<content select='#m11'></content>" "<a id='s11'>s11</a>" "<a id='s12'>" "<content select='#m10'></content>" "</a>"; setupSampleHTML(mainHTML, shadowHTML, 1); RefPtrWillBeRawPtr<Element> body = document().body(); RefPtrWillBeRawPtr<Element> m0 = body->querySelector("#m0", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m1 = body->querySelector("#m1", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m2 = body->querySelector("#m2", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> m10 = body->querySelector("#m10", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = m1->openShadowRoot(); RefPtrWillBeRawPtr<Element> s11 = shadowRoot->querySelector("#s11", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> s12 = shadowRoot->querySelector("#s12", ASSERT_NO_EXCEPTION); EXPECT_EQ(m0->firstChild(), ComposedTreeTraversal::lastWithin(*m0)); EXPECT_EQ(*m0->firstChild(), ComposedTreeTraversal::lastWithinOrSelf(*m0)); EXPECT_EQ(m10->firstChild(), ComposedTreeTraversal::lastWithin(*m1)); EXPECT_EQ(*m10->firstChild(), ComposedTreeTraversal::lastWithinOrSelf(*m1)); EXPECT_EQ(nullptr, ComposedTreeTraversal::lastWithin(*m2)); EXPECT_EQ(*m2, ComposedTreeTraversal::lastWithinOrSelf(*m2)); EXPECT_EQ(s11->firstChild(), ComposedTreeTraversal::lastWithin(*s11)); EXPECT_EQ(*s11->firstChild(), ComposedTreeTraversal::lastWithinOrSelf(*s11)); EXPECT_EQ(m10->firstChild(), ComposedTreeTraversal::lastWithin(*s12)); EXPECT_EQ(*m10->firstChild(), ComposedTreeTraversal::lastWithinOrSelf(*s12)); }
TEST_F(FlatTreeTraversalTest, redistribution) { const char* mainHTML = "<div id='m0'>m0</div>" "<div id='m1'>" "<span id='m10'>m10</span>" "<span id='m11'>m11</span>" "</div>" "<div id='m2'>m2</div>"; const char* shadowHTML1 = "<div id='s1'>" "<content></content>" "</div>"; setupSampleHTML(mainHTML, shadowHTML1, 1); const char* shadowHTML2 = "<div id='s2'>" "<content select='#m10'></content>" "<span id='s21'>s21</span>" "</div>"; Element* body = document().body(); Element* m1 = body->querySelector("#m1"); Element* m10 = body->querySelector("#m10"); ShadowRoot* shadowRoot1 = m1->openShadowRoot(); Element* s1 = shadowRoot1->querySelector("#s1"); attachV0ShadowRoot(*s1, shadowHTML2); ShadowRoot* shadowRoot2 = s1->openShadowRoot(); Element* s21 = shadowRoot2->querySelector("#s21"); EXPECT_EQ(s21, FlatTreeTraversal::nextSibling(*m10)); EXPECT_EQ(m10, FlatTreeTraversal::previousSibling(*s21)); // FlatTreeTraversal::traverseSiblings does not work for a node which is not // in a document flat tree. // e.g. The following test fails. The result of // FlatTreeTraversal::previousSibling(*m11)) will be #m10, instead of nullptr. // Element* m11 = body->querySelector("#m11"); // EXPECT_EQ(nullptr, FlatTreeTraversal::previousSibling(*m11)); }
// Test case for // - lastWithin // - lastWithinOrSelf TEST_F(FlatTreeTraversalTest, lastWithin) { const char* mainHTML = "<div id='m0'>m0</div>" "<div id='m1'>" "<span id='m10'>m10</span>" "<span id='m11'>m11</span>" "<span id='m12'>m12</span>" // #m12 is not distributed. "</div>" "<div id='m2'></div>"; const char* shadowHTML = "<content select='#m11'></content>" "<a id='s11'>s11</a>" "<a id='s12'>" "<content select='#m10'></content>" "</a>"; setupSampleHTML(mainHTML, shadowHTML, 1); Element* body = document().body(); Element* m0 = body->querySelector("#m0"); Element* m1 = body->querySelector("#m1"); Element* m2 = body->querySelector("#m2"); Element* m10 = body->querySelector("#m10"); ShadowRoot* shadowRoot = m1->openShadowRoot(); Element* s11 = shadowRoot->querySelector("#s11"); Element* s12 = shadowRoot->querySelector("#s12"); EXPECT_EQ(m0->firstChild(), FlatTreeTraversal::lastWithin(*m0)); EXPECT_EQ(*m0->firstChild(), FlatTreeTraversal::lastWithinOrSelf(*m0)); EXPECT_EQ(m10->firstChild(), FlatTreeTraversal::lastWithin(*m1)); EXPECT_EQ(*m10->firstChild(), FlatTreeTraversal::lastWithinOrSelf(*m1)); EXPECT_EQ(nullptr, FlatTreeTraversal::lastWithin(*m2)); EXPECT_EQ(*m2, FlatTreeTraversal::lastWithinOrSelf(*m2)); EXPECT_EQ(s11->firstChild(), FlatTreeTraversal::lastWithin(*s11)); EXPECT_EQ(*s11->firstChild(), FlatTreeTraversal::lastWithinOrSelf(*s11)); EXPECT_EQ(m10->firstChild(), FlatTreeTraversal::lastWithin(*s12)); EXPECT_EQ(*m10->firstChild(), FlatTreeTraversal::lastWithinOrSelf(*s12)); }
TEST_F(ComposedTreeTraversalTest, nextSiblingNotInDocumentComposedTree) { const char* mainHTML = "<div id='m0'>m0</div>" "<div id='m1'>" "<span id='m10'>m10</span>" "<span id='m11'>m11</span>" "</div>" "<div id='m2'>m2</div>"; const char* shadowHTML = "<content select='#m11'></content>"; setupSampleHTML(mainHTML, shadowHTML, 1); RefPtrWillBeRawPtr<Element> body = document().body(); RefPtrWillBeRawPtr<Element> m10 = body->querySelector("#m10", ASSERT_NO_EXCEPTION); EXPECT_EQ(nullptr, ComposedTreeTraversal::nextSibling(*m10)); EXPECT_EQ(nullptr, ComposedTreeTraversal::previousSibling(*m10)); }
// Test case for // - commonAncestor // - isDescendantOf TEST_F(FlatTreeTraversalTest, commonAncestor) { // We build following flat tree: // ____BODY___ // | | | // m0 m1 m2 m1 is shadow host having m10, m11, m12. // _|_ | __|__ // | | | | | // m00 m01 | m20 m21 // _____|_____________ // | | | | | // s10 s11 s12 s13 s14 // | // __|__ // | | | // m12 m10 m11 <-- distributed // where: each symbol consists with prefix, child index, child-child index. // prefix "m" means node in main tree, // prefix "d" means node in main tree and distributed // prefix "s" means node in shadow tree const char* mainHTML = "<a id='m0'><b id='m00'>m00</b><b id='m01'>m01</b></a>" "<a id='m1'>" "<b id='m10'>m10</b>" "<b id='m11'>m11</b>" "<b id='m12'>m12</b>" "</a>" "<a id='m2'><b id='m20'>m20</b><b id='m21'>m21</b></a>"; const char* shadowHTML = "<a id='s10'>s10</a>" "<a id='s11'><content select='#m12'></content></a>" "<a id='s12'>s12</a>" "<a id='s13'>" "<content select='#m10'></content>" "<content select='#m11'></content>" "</a>" "<a id='s14'>s14</a>"; setupSampleHTML(mainHTML, shadowHTML, 1); Element* body = document().body(); Element* m0 = body->querySelector("#m0"); Element* m1 = body->querySelector("#m1"); Element* m2 = body->querySelector("#m2"); Element* m00 = body->querySelector("#m00"); Element* m01 = body->querySelector("#m01"); Element* m10 = body->querySelector("#m10"); Element* m11 = body->querySelector("#m11"); Element* m12 = body->querySelector("#m12"); Element* m20 = body->querySelector("#m20"); Element* m21 = body->querySelector("#m21"); ShadowRoot* shadowRoot = m1->openShadowRoot(); Element* s10 = shadowRoot->querySelector("#s10"); Element* s11 = shadowRoot->querySelector("#s11"); Element* s12 = shadowRoot->querySelector("#s12"); Element* s13 = shadowRoot->querySelector("#s13"); Element* s14 = shadowRoot->querySelector("#s14"); testCommonAncestor(body, *m0, *m1); testCommonAncestor(body, *m1, *m2); testCommonAncestor(body, *m1, *m20); testCommonAncestor(body, *s14, *m21); testCommonAncestor(m0, *m0, *m0); testCommonAncestor(m0, *m00, *m01); testCommonAncestor(m1, *m1, *m1); testCommonAncestor(m1, *s10, *s14); testCommonAncestor(m1, *s10, *m12); testCommonAncestor(m1, *s12, *m12); testCommonAncestor(m1, *m10, *m12); testCommonAncestor(m01, *m01, *m01); testCommonAncestor(s11, *s11, *m12); testCommonAncestor(s13, *m10, *m11); s12->remove(ASSERT_NO_EXCEPTION); testCommonAncestor(s12, *s12, *s12); testCommonAncestor(nullptr, *s12, *s11); testCommonAncestor(nullptr, *s12, *m01); testCommonAncestor(nullptr, *s12, *m20); m20->remove(ASSERT_NO_EXCEPTION); testCommonAncestor(m20, *m20, *m20); testCommonAncestor(nullptr, *m20, *s12); testCommonAncestor(nullptr, *m20, *m1); }