// 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));
}
Exemplo n.º 2
0
// 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));
}
Exemplo n.º 3
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()));
}
Exemplo n.º 6
0
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));
}
Exemplo n.º 8
0
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));
}
Exemplo n.º 9
0
// 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));
}
Exemplo n.º 11
0
// 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);
}