// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "app/tree_node_model.h" #include "base/string16.h" #include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" class TreeNodeModelTest : public testing::Test, public TreeModelObserver { public: TreeNodeModelTest() : added_count_(0), removed_count_(0), changed_count_(0) {} void AssertObserverCount(int added_count, int removed_count, int changed_count) { ASSERT_EQ(added_count, added_count_); ASSERT_EQ(removed_count, removed_count_); ASSERT_EQ(changed_count, changed_count_); } void ClearCounts() { added_count_ = removed_count_ = changed_count_ = 0; } // Begin TreeModelObserver implementation. virtual void TreeNodesAdded(TreeModel* model, TreeModelNode* parent, int start, int count) { added_count_++; } virtual void TreeNodesRemoved(TreeModel* model, TreeModelNode* parent, int start, int count) { removed_count_++; } virtual void TreeNodeChanged(TreeModel* model, TreeModelNode* node) { changed_count_++; } // End TreeModelObserver implementation. private: int added_count_; int removed_count_; int changed_count_; DISALLOW_COPY_AND_ASSIGN(TreeNodeModelTest); }; // Verify if the model is properly adding a new node in the tree and // notifying the observers. // The tree looks like this: // root // |-- child1 // | |-- foo1 // | |-- foo2 // +-- child2 TEST_F(TreeNodeModelTest, AddNode) { TreeNodeWithValue* root = new TreeNodeWithValue(ASCIIToUTF16("root"), 0); TreeNodeModel > model(root); model.AddObserver(this); ClearCounts(); // Create the first root child. TreeNodeWithValue* child1 = new TreeNodeWithValue(ASCIIToUTF16("child 1"), 1); model.Add(root, 0, child1); AssertObserverCount(1, 0, 0); // Add two nodes under the |child1|. TreeNodeWithValue* foo1 = new TreeNodeWithValue(ASCIIToUTF16("foo1"), 3); TreeNodeWithValue* foo2 = new TreeNodeWithValue(ASCIIToUTF16("foo2"), 4); child1->Add(0, foo1); child1->Add(1, foo2); // Create the second root child. TreeNodeWithValue* child2 = new TreeNodeWithValue(ASCIIToUTF16("child 2"), 2); root->Add(1, child2); // Check if there is two nodes under the root. ASSERT_EQ(2, model.GetChildCount(root)); // Check if there is two nodes under |child1|. ASSERT_EQ(2, model.GetChildCount(child1)); // Check if there is none nodes under |child2|. ASSERT_EQ(0, model.GetChildCount(child2)); } // Verify if the model is properly removing a node from the tree // and notifying the observers. TEST_F(TreeNodeModelTest, RemoveNode) { TreeNodeWithValue* root = new TreeNodeWithValue(ASCIIToUTF16("root"), 0); TreeNodeModel > model(root); model.AddObserver(this); ClearCounts(); // Create the first child node. TreeNodeWithValue* child1 = new TreeNodeWithValue(ASCIIToUTF16("child 1"), 1); // And add it to the root node. root->Add(0, child1); ASSERT_EQ(1, model.GetChildCount(root)); // Now remove the |child1| from root and release the memory. delete model.Remove(root, 0); AssertObserverCount(0, 1, 0); ASSERT_EQ(0, model.GetChildCount(root)); } // Verify if the nodes added under the root are all deleted when calling // RemoveAll. Note that is responsability of the caller to free the memory // of the nodes removed after RemoveAll is called. // The tree looks like this: // root // |-- child1 // | |-- foo1 // | |-- child0 // | |-- child1 // +-------|-- child2 TEST_F(TreeNodeModelTest, RemoveAllNodes) { TreeNodeWithValue* root = new TreeNodeWithValue(ASCIIToUTF16("root"), 0); TreeNodeModel > model(root); model.AddObserver(this); ClearCounts(); // Create the first child node. TreeNodeWithValue* child1 = new TreeNodeWithValue(ASCIIToUTF16("child 1"), 1); model.Add(root, 0, child1); TreeNodeWithValue* foo1 = new TreeNodeWithValue(ASCIIToUTF16("foo1"), 2); model.Add(child1, 0, foo1); // Add some nodes to |foo1|. for (int i = 0; i < 3; ++i) { model.Add(foo1, i, new TreeNodeWithValue(ASCIIToUTF16("child") + base::IntToString16(i), i)); } ASSERT_EQ(3, model.GetChildCount(foo1)); // Now remove all nodes from root. root->RemoveAll(); // Release memory, so we don't leak. delete child1; ASSERT_EQ(0, model.GetChildCount(root)); } // Verify if the model returns correct indexes for the specified nodes. // The tree looks like this: // root // |-- child1 // | |-- foo1 // +-- child2 TEST_F(TreeNodeModelTest, IndexOfChild) { TreeNodeWithValue* root = new TreeNodeWithValue(ASCIIToUTF16("root"), 0); TreeNodeModel > model(root); model.AddObserver(this); ClearCounts(); TreeNodeWithValue* child1 = new TreeNodeWithValue(ASCIIToUTF16("child 1"), 1); model.Add(root, 0, child1); TreeNodeWithValue* child2 = new TreeNodeWithValue(ASCIIToUTF16("child 2"), 2); model.Add(root, 1, child2); TreeNodeWithValue* foo1 = new TreeNodeWithValue(ASCIIToUTF16("foo1"), 0); model.Add(child1, 0, foo1); ASSERT_EQ(0, model.IndexOfChild(root, child1)); ASSERT_EQ(1, model.IndexOfChild(root, child2)); ASSERT_EQ(0, model.IndexOfChild(child1, foo1)); ASSERT_EQ(-1, model.IndexOfChild(root, foo1)); } // Verify whether a specified node has or not an ancestor. // The tree looks like this: // root // |-- child1 // |-- child2 TEST_F(TreeNodeModelTest, HasAncestor) { TreeNodeWithValue* root = new TreeNodeWithValue(ASCIIToUTF16("root"), 0); TreeNodeModel > model(root); TreeNodeWithValue* child1 = new TreeNodeWithValue(ASCIIToUTF16("child 1"), 0); model.Add(root, 0, child1); TreeNodeWithValue* child2 = new TreeNodeWithValue(ASCIIToUTF16("child 2"), 1); model.Add(root, 1, child2); ASSERT_TRUE(root->HasAncestor(root)); ASSERT_FALSE(root->HasAncestor(child1)); ASSERT_TRUE(child1->HasAncestor(root)); ASSERT_FALSE(child1->HasAncestor(child2)); ASSERT_FALSE(child2->HasAncestor(child1)); } // The tree looks like this: // root // |-- child1 // | |-- child2 // | |-- child3 // |-- foo1 // | |-- foo2 // | |-- foo3 // | |-- foo4 // +-- bar1 // // The TotalNodeCount of root is: 9 // The TotalNodeCount of child1 is: 3 // The TotalNodeCount of bar1 is: 1 // And so on... // The purpose here is to verify if the function returns the total of nodes // under the specifed node correctly. The count should include the node it self. TEST_F(TreeNodeModelTest, GetTotalNodeCount) { TreeNodeWithValue* root = new TreeNodeWithValue(ASCIIToUTF16("root"), 0); TreeNodeModel > model(root); TreeNodeWithValue* child1 = new TreeNodeWithValue(ASCIIToUTF16("child1"), 1); TreeNodeWithValue* child2 = new TreeNodeWithValue(ASCIIToUTF16("child2"), 2); TreeNodeWithValue* child3 = new TreeNodeWithValue(ASCIIToUTF16("child3"), 3); TreeNodeWithValue* foo1 = new TreeNodeWithValue(ASCIIToUTF16("foo1"), 4); TreeNodeWithValue* foo2 = new TreeNodeWithValue(ASCIIToUTF16("foo2"), 5); TreeNodeWithValue* foo3 = new TreeNodeWithValue(ASCIIToUTF16("foo3"), 6); TreeNodeWithValue* foo4 = new TreeNodeWithValue(ASCIIToUTF16("foo4"), 7); TreeNodeWithValue* bar1 = new TreeNodeWithValue(ASCIIToUTF16("bar1"), 8); model.Add(root, 0, child1); model.Add(child1, 0, child2); model.Add(child2, 0, child3); model.Add(root, 1, foo1); model.Add(foo1, 0, foo2); model.Add(foo1, 1, foo4); model.Add(foo2, 0, foo3); model.Add(root, 0, bar1); ASSERT_EQ(9, root->GetTotalNodeCount()); ASSERT_EQ(3, child1->GetTotalNodeCount()); ASSERT_EQ(1, bar1->GetTotalNodeCount()); ASSERT_EQ(2, foo2->GetTotalNodeCount()); } // Makes sure that we are notified when the node is renamed, // also makes sure the node is properly renamed. TEST_F(TreeNodeModelTest, SetTitle) { TreeNodeWithValue* root = new TreeNodeWithValue(ASCIIToUTF16("root"), 0); TreeNodeModel > model(root); model.AddObserver(this); ClearCounts(); const string16 title(ASCIIToUTF16("root2")); model.SetTitle(root, title); AssertObserverCount(0, 0, 1); EXPECT_EQ(title, root->GetTitle()); }