| // 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 |