text: // Copyright 2017-2020 The Verible Authors.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //      http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  // Sanity tests for tree node construction functions.
  
  #include "common/text/concrete_syntax_tree.h"
  
  #include <memory>
  #include <utility>
  
  #include "gmock/gmock.h"
  #include "gtest/gtest.h"
  #include "common/text/concrete_syntax_leaf.h"
  #include "common/text/symbol.h"
  #include "common/text/tree_builder_test_util.h"
  #include "common/text/tree_compare.h"
  #include "common/util/logging.h"
  
  namespace verible {
  
  namespace {
  
  using ::testing::IsEmpty;
  using ::testing::IsNull;
  using ::testing::NotNull;
  using ::testing::SizeIs;
  
  static void SinkValue(SymbolPtr) {
    // Do nothing, just consume and expire the pointer.
  }
  
  static SyntaxTreeNode* CheckTree(const SymbolPtr& ptr) {
    CHECK(ptr->Kind() == SymbolKind::kNode);
    return down_cast<SyntaxTreeNode*>(ptr.get());
  }
  
  // Test that MatchesTag matches correctly.
  TEST(SyntaxTreeNodeMatchesTag, Matches) {
    auto node = MakeTaggedNode(3);
    EXPECT_TRUE(CheckTree(node)->MatchesTag(3));
  }
  
  // Test that MatchesTag does not match.
  TEST(SyntaxTreeNodeMatchesTag, NotMatches) {
    auto node = MakeTaggedNode(4);
    EXPECT_FALSE(CheckTree(node)->MatchesTag(3));
  }
  
  // Test that MatchesTagAnyOf matches correctly.
  TEST(SyntaxTreeNodeMatchesTagAnyOf, Matches) {
    auto node = MakeTaggedNode(3);
    EXPECT_TRUE(CheckTree(node)->MatchesTagAnyOf({2, 3}));
    EXPECT_TRUE(CheckTree(node)->MatchesTagAnyOf({3, 4}));
    EXPECT_FALSE(CheckTree(node)->MatchesTagAnyOf({2, 4}));
  }
  
  TEST(SyntaxTreeNodeAppend, AppendVoid) {
    SyntaxTreeNode node;
    node.Append();
    EXPECT_THAT(node.children(), IsEmpty());
  }
  
  // Test that std::move is automated.
  TEST(SyntaxTreeNodeAppend, AppendChildReference) {
    SyntaxTreeNode node;
    SymbolPtr child;
    node.Append(child);
    EXPECT_THAT(node.children(), SizeIs(1));
  }
  
  // Test that redundant move is accepted.
  TEST(SyntaxTreeNodeAppend, AppendChildMoved) {
    SyntaxTreeNode node;
    SymbolPtr child;
    node.Append(std::move(child));
    EXPECT_THAT(node.children(), SizeIs(1));
  }
  
  // Test that temporary value is properly forwarded.
  TEST(SyntaxTreeNodeAppend, AppendChildTemporary) {
    SyntaxTreeNode node;
    node.Append(SymbolPtr());
    EXPECT_THAT(node.children(), SizeIs(1));
  }
  
  // Test that nullptrs can be appended.
  TEST(SyntaxTreeNodeAppend, AppendChildNullPtr) {
    SyntaxTreeNode node;
    node.Append(nullptr);
    EXPECT_THAT(node.children(), SizeIs(1));
  }
  
  // Test that ownership is transferred to sink functions.
  TEST(MakeNodeTest, EmptyConstructor) {
    auto node = MakeNode();
    EXPECT_THAT(node, NotNull());
    SinkValue(std::move(node));
    EXPECT_THAT(node, IsNull());
  }
  
  // Test that out-of-bounds is caught.
  TEST(MakeNodeTest, ChildrenOutOfBounds) {
    SyntaxTreeNode node;
    EXPECT_DEATH(node[0], "");
  }
  
  // Test that out-of-bounds is caught (const).
  TEST(MakeNodeTest, ChildrenOutOfBoundsConst) {
    const SyntaxTreeNode node;
    EXPECT_DEATH(node[0], "");
  }
  
  TEST(MakeNodeTest, SinkTemporary) { SinkValue(MakeNode()); }
  
  // Test construction of tagged node.
  TEST(MakeNodeTest, TaggedEmptyConstructor) {
    const int tag = 10;
    auto node = MakeTaggedNode(tag);
    ASSERT_THAT(node, NotNull());
    EXPECT_THAT(CheckTree(node)->children(), IsEmpty());
  }
  
  // Test construction of tagged node.
  TEST(MakeNodeTest, ImmediateTaggedEmptyConstructor) {
    auto node = MakeTaggedNode(20);
    ASSERT_THAT(node, NotNull());
    EXPECT_THAT(CheckTree(node)->children(), IsEmpty());
  }
  
  // Test construction of untagged node with one child.
  TEST(MakeNodeTest, SingleChild) {
    auto child = MakeNode();
    EXPECT_THAT(child, NotNull());
    auto parent = MakeNode(child);
    EXPECT_THAT(parent, NotNull());
    EXPECT_THAT(child, IsNull());
    EXPECT_THAT(CheckTree(parent)->children(), SizeIs(1));
  }
  
  // Test construction of untagged node with one (temporary) child.
  TEST(MakeNodeTest, SingleChildTemporary) {
    auto parent = MakeNode(MakeNode());
    EXPECT_THAT(parent, NotNull());
    EXPECT_THAT(CheckTree(parent)->children(), SizeIs(1));
  }
  
  // Test construction of untagged node with multiple children.
  TEST(MakeNodeTest, MultiChild) {
    auto child1 = MakeNode();
    auto child2 = MakeNode();
    auto child3 = MakeNode();
    EXPECT_THAT(child1, NotNull());
    EXPECT_THAT(child2, NotNull());
    EXPECT_THAT(child3, NotNull());
    auto parent = MakeNode(child1, child2, child3);
    ASSERT_THAT(parent, NotNull());
    EXPECT_THAT(child1, IsNull());
    EXPECT_THAT(child2, IsNull());
    EXPECT_THAT(child3, IsNull());
    EXPECT_THAT(CheckTree(parent)->children(), SizeIs(3));
  }
  
  // Test ExtendNode with nothing to extend (base case).
  TEST(ExtendNodeTest, ExtendNone) {
    auto seq = MakeNode();
    EXPECT_THAT(seq, NotNull());
    auto seq2 = ExtendNode(seq);
    EXPECT_THAT(seq2, NotNull());
    EXPECT_THAT(seq, IsNull());
    EXPECT_THAT(CheckTree(seq2)->children(), IsEmpty());
  }
  
  // Test extending node with one child.
  TEST(ExtendNodeTest, ExtendOne) {
    auto seq = MakeNode();
    auto item = MakeNode();
    EXPECT_THAT(seq, NotNull());
    EXPECT_THAT(item, NotNull());
    auto seq2 = ExtendNode(seq, item);
    EXPECT_THAT(seq2, NotNull());
    EXPECT_THAT(seq, IsNull());
    EXPECT_THAT(item, IsNull());
    EXPECT_THAT(CheckTree(seq2)->children(), SizeIs(1));
  }
  
  // Test extending node with multiple children.
  TEST(ExtendNodeTest, ExtendMulti) {
    auto seq = MakeNode();
    auto item1 = MakeNode();
    auto item2 = MakeNode();
    auto item3 = MakeNode();
    EXPECT_THAT(seq, NotNull());
    EXPECT_THAT(item1, NotNull());
    EXPECT_THAT(item2, NotNull());
    EXPECT_THAT(item3, NotNull());
    auto seq2 = ExtendNode(seq, item1, item2, item3);
    EXPECT_THAT(seq2, NotNull());
    EXPECT_THAT(seq, IsNull());
    EXPECT_THAT(item1, IsNull());
    EXPECT_THAT(item2, IsNull());
    EXPECT_THAT(item3, IsNull());
    EXPECT_THAT(CheckTree(seq2)->children(), SizeIs(3));
  }
  
  // Test extending node with multiple (temporary) children.
  TEST(ExtendNodeTest, ExtendMultiTemporary) {
    auto seq = MakeNode();
    EXPECT_THAT(seq, NotNull());
    auto seq2 = ExtendNode(seq, MakeNode(), MakeNode());
    ASSERT_THAT(seq2, NotNull());
    EXPECT_THAT(seq, IsNull());
    EXPECT_THAT(CheckTree(seq2)->children(), SizeIs(2));
  }
  
  // Test extending node with temporary parent.
  TEST(ExtendNodeTest, ExtendTemporaryNodeNoChildren) {
    auto seq = ExtendNode(MakeNode());
    ASSERT_THAT(seq, NotNull());
    EXPECT_THAT(CheckTree(seq)->children(), IsEmpty());
  }
  
  // Test extending node with temporary parent with temporary children.
  TEST(ExtendNodeTest, ExtendTemporaryNode) {
    auto seq = ExtendNode(MakeNode(), MakeNode(), MakeNode());
    ASSERT_THAT(seq, NotNull());
    EXPECT_THAT(CheckTree(seq)->children(), SizeIs(2));
  }
  
  // Test forwarding empty set of children to new node.
  TEST(SyntaxTreeNodeAppend, AdoptChildrenNone) {
    auto seq = MakeNode();
    auto parent = MakeNode(ForwardChildren(seq));
    EXPECT_THAT(seq, IsNull());
    EXPECT_THAT(CheckTree(parent)->children(), IsEmpty());
  }
  
  // Test forwarding empty set of children to new node.
  TEST(SyntaxTreeNodeAppend, AdoptLeaf) {
    auto leaf = std::unique_ptr<Symbol>(new SyntaxTreeLeaf(0, "abc"));
    auto parent = MakeNode(ForwardChildren(leaf));
    EXPECT_THAT(leaf, IsNull());
    EXPECT_THAT(CheckTree(parent)->children(), SizeIs(1));
  }
  
  // Test forwarding set of children to new node, transferring ownership.
  TEST(SyntaxTreeNodeAppend, AdoptChildren) {
    auto seq = MakeNode(MakeNode(), MakeNode(), MakeNode());
    auto parent = MakeNode(ForwardChildren(seq));
    EXPECT_THAT(seq, IsNull());
    auto parentnode = CheckTree(parent);
    EXPECT_THAT(parentnode->children(), SizeIs(3));
    for (const auto& child : parentnode->children()) {
      EXPECT_THAT(child, NotNull());
    }
  }
  
  // Test forwarding set of null children to new node.
  TEST(SyntaxTreeNodeAppend, AdoptNullChildren) {
    auto seq = MakeNode(nullptr, nullptr);
    auto parent = MakeNode(ForwardChildren(seq));
    EXPECT_THAT(seq, IsNull());
    auto parentnode = CheckTree(parent);
    EXPECT_THAT(parentnode->children(), SizeIs(2));
    for (const auto& child : parentnode->children()) {
      EXPECT_THAT(child, IsNull());
    }
  }
  
  /*
  // Test forwarding of children of null parent
  TEST(SyntaxTreeNodeAppend, AdoptChildrenNullParent) {
    auto seq = nullptr;
    auto parent = MakeNode(ForwardChildren(seq));
    auto parentnode = CheckTree(parent);
    ASSERT_THAT(parentnode, NotNull());
    EXPECT_THAT(parentnode->children(), IsEmpty());
  }
  
  // Test forwarding of children of null parent
  TEST(SyntaxTreeNodeAppend, AdoptChildrenNullParentDirect) {
    auto parent = MakeNode(ForwardChildren(nullptr));
    auto parentnode = CheckTree(parent);
    ASSERT_THAT(parentnode, NotNull());
    EXPECT_THAT(parentnode->children(), IsEmpty());
  }
  */
  
  // Test mix of forwarded and non-forwarded children.
  TEST(SyntaxTreeNodeAppend, AdoptChildrenMixed) {
    auto seq = MakeNode(MakeNode(), MakeNode(), MakeNode());
    auto parent = MakeNode(MakeNode(), ForwardChildren(seq), MakeNode());
    EXPECT_THAT(seq, IsNull());
    auto parentnode = CheckTree(parent);
    ASSERT_THAT(parentnode, NotNull());
    EXPECT_THAT(parentnode->children(), SizeIs(5));
    for (const auto& child : parentnode->children()) {
      EXPECT_THAT(child, NotNull());
    }
  }
  
  // Test multiple of forwarded sets of children.
  TEST(SyntaxTreeNodeAppend, AdoptChildrenMultiple) {
    auto seq = MakeNode(MakeNode(), MakeNode(), MakeNode());
    auto seq2 = MakeNode(MakeNode(), MakeNode(), MakeNode(), MakeNode());
    auto parent = MakeNode(ForwardChildren(seq), ForwardChildren(seq2));
    EXPECT_THAT(seq, IsNull());
    EXPECT_THAT(seq2, IsNull());
    auto parentnode = CheckTree(parent);
    ASSERT_THAT(parentnode, NotNull());
    EXPECT_THAT(parentnode->children(), SizeIs(7));
    for (const auto& child : parentnode->children()) {
      EXPECT_THAT(child, NotNull());
    }
  }
  
  // Test extending one set with forwarded children.
  TEST(ExtendNodeTest, AdoptChildren) {
    auto seq = ExtendNode(MakeNode(), MakeNode(), MakeNode());
    auto parent = MakeNode(ForwardChildren(seq));
    EXPECT_THAT(seq, IsNull());
    auto parentnode = CheckTree(parent);
    EXPECT_THAT(parentnode->children(), SizeIs(2));
    for (const auto& child : parentnode->children()) {
      EXPECT_THAT(child, NotNull());
    }
  }
  
  // Test extending temporary parent with forwarded children.
  TEST(ExtendNodeTest, AdoptChildrenMixed) {
    auto seq = MakeNode(MakeNode(), MakeNode(), MakeNode());
    auto parent = ExtendNode(MakeNode(), ForwardChildren(seq), MakeNode());
    EXPECT_THAT(seq, IsNull());
    auto parentnode = CheckTree(parent);
    EXPECT_THAT(parentnode->children(), SizeIs(4));
    for (const auto& child : parentnode->children()) {
      EXPECT_THAT(child, NotNull());
    }
  }
  
  // Tests setting a placeholder to a single leaf
  TEST(ExtendNodeTest, SetChild0Size1) {
    auto expected = Node(Leaf(4, "z"));
  
    auto node1 = Node(nullptr);
    auto node2 = Leaf(4, "y");
    SetChild(node1, 0, node2);
    EXPECT_THAT(node1, NotNull());
    EXPECT_THAT(node2, IsNull());
    EXPECT_THAT(CheckTree(node1)->children(), SizeIs(1));
    EXPECT_TRUE(EqualTreesByEnum(expected.get(), node1.get()));
  }
  
  // Tests setting a placeholder to a more complex tree
  TEST(ExtendNodeTest, SetChild1Size2) {
    auto expected = Node(Leaf(1, "a"), Node(Leaf(4, "b")));
  
    auto node1 = Node(Leaf(1, "a"), nullptr);
    auto node2 = Node(Leaf(4, "b"));
    SetChild(node1, 1, node2);
    EXPECT_THAT(node1, NotNull());
    EXPECT_THAT(node2, IsNull());
    EXPECT_THAT(CheckTree(node1)->children(), SizeIs(2));
    EXPECT_TRUE(EqualTreesByEnum(expected.get(), node1.get()));
  }
  
  // Tests that subscript operator works (mutable).
  TEST(NodeSubscriptTest, MutableReference) {
    auto example = Node(Leaf(6, "6"), Leaf(7, "7"));
    auto& example_node = down_cast<SyntaxTreeNode&>(*example);
    EXPECT_EQ(example_node[0]->Tag().tag, 6);
    EXPECT_EQ(example_node[1]->Tag().tag, 7);
  }
  
  // Tests that subscript operator works (const).
  TEST(NodeSubscriptTest, ConstReference) {
    auto example = Node(Leaf(8, "8"), Leaf(9, "9"));
    const auto& example_node = down_cast<const SyntaxTreeNode&>(*example);
    EXPECT_EQ(example_node[0]->Tag().tag, 8);
    EXPECT_EQ(example_node[1]->Tag().tag, 9);
  }
  
  }  // namespace
  }  // namespace verible
  