Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / views / controls / tree / tree_view_unittest.cc
blob0af68a9c76b3459936b5fcf39264cabdbe5dab57
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/controls/tree/tree_view.h"
7 #include <string>
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "ui/base/models/tree_node_model.h"
12 #include "ui/views/controls/prefix_selector.h"
13 #include "ui/views/controls/textfield/textfield.h"
14 #include "ui/views/test/views_test_base.h"
16 using ui::TreeModel;
17 using ui::TreeModelNode;
18 using ui::TreeNode;
20 using base::ASCIIToUTF16;
22 namespace views {
24 class TestNode : public TreeNode<TestNode> {
25 public:
26 TestNode() {}
27 ~TestNode() override {}
29 private:
30 DISALLOW_COPY_AND_ASSIGN(TestNode);
33 // Creates the following structure:
34 // 'root'
35 // 'a'
36 // 'b'
37 // 'b1'
38 // 'c'
39 class TreeViewTest : public ViewsTestBase {
40 public:
41 TreeViewTest() : model_(new TestNode) {
42 static_cast<TestNode*>(model_.GetRoot())->SetTitle(ASCIIToUTF16("root"));
43 Add(model_.GetRoot(), 0, "a");
44 Add(Add(model_.GetRoot(), 1, "b"), 0, "b1");
45 Add(model_.GetRoot(), 2, "c");
48 protected:
49 TestNode* Add(TestNode* parent,
50 int index,
51 const std::string& title);
53 std::string TreeViewContentsAsString();
55 std::string GetSelectedNodeTitle();
57 std::string GetEditingNodeTitle();
59 TestNode* GetNodeByTitle(const std::string& title);
61 void IncrementSelection(bool next);
62 void CollapseOrSelectParent();
63 void ExpandOrSelectChild();
64 int GetRowCount();
65 PrefixSelector* selector() { return tree_.GetPrefixSelector(); }
67 ui::TreeNodeModel<TestNode > model_;
68 TreeView tree_;
70 private:
71 std::string InternalNodeAsString(TreeView::InternalNode* node);
73 TestNode* GetNodeByTitleImpl(TestNode* node, const base::string16& title);
75 DISALLOW_COPY_AND_ASSIGN(TreeViewTest);
78 TestNode* TreeViewTest::Add(TestNode* parent,
79 int index,
80 const std::string& title) {
81 TestNode* new_node = new TestNode;
82 new_node->SetTitle(ASCIIToUTF16(title));
83 model_.Add(parent, new_node, index);
84 return new_node;
87 std::string TreeViewTest::TreeViewContentsAsString() {
88 return InternalNodeAsString(&tree_.root_);
91 std::string TreeViewTest::GetSelectedNodeTitle() {
92 TreeModelNode* model_node = tree_.GetSelectedNode();
93 return model_node ? base::UTF16ToASCII(model_node->GetTitle())
94 : std::string();
97 std::string TreeViewTest::GetEditingNodeTitle() {
98 TreeModelNode* model_node = tree_.GetEditingNode();
99 return model_node ? base::UTF16ToASCII(model_node->GetTitle())
100 : std::string();
103 TestNode* TreeViewTest::GetNodeByTitle(const std::string& title) {
104 return GetNodeByTitleImpl(model_.GetRoot(), ASCIIToUTF16(title));
107 void TreeViewTest::IncrementSelection(bool next) {
108 tree_.IncrementSelection(next ? TreeView::INCREMENT_NEXT :
109 TreeView::INCREMENT_PREVIOUS);
112 void TreeViewTest::CollapseOrSelectParent() {
113 tree_.CollapseOrSelectParent();
116 void TreeViewTest::ExpandOrSelectChild() {
117 tree_.ExpandOrSelectChild();
120 int TreeViewTest::GetRowCount() {
121 return tree_.GetRowCount();
124 TestNode* TreeViewTest::GetNodeByTitleImpl(TestNode* node,
125 const base::string16& title) {
126 if (node->GetTitle() == title)
127 return node;
128 for (int i = 0; i < node->child_count(); ++i) {
129 TestNode* child = GetNodeByTitleImpl(node->GetChild(i), title);
130 if (child)
131 return child;
133 return NULL;
136 std::string TreeViewTest::InternalNodeAsString(
137 TreeView::InternalNode* node) {
138 std::string result = base::UTF16ToASCII(node->model_node()->GetTitle());
139 if (node->is_expanded() && node->child_count()) {
140 result += " [";
141 for (int i = 0; i < node->child_count(); ++i) {
142 if (i > 0)
143 result += " ";
144 result += InternalNodeAsString(node->GetChild(i));
146 result += "]";
148 return result;
151 // Verifies setting model correctly updates internal state.
152 TEST_F(TreeViewTest, SetModel) {
153 tree_.SetModel(&model_);
154 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
155 EXPECT_EQ("root", GetSelectedNodeTitle());
156 EXPECT_EQ(4, GetRowCount());
159 // Verifies SetSelectedNode works.
160 TEST_F(TreeViewTest, SetSelectedNode) {
161 tree_.SetModel(&model_);
162 EXPECT_EQ("root", GetSelectedNodeTitle());
164 // NULL should clear the selection.
165 tree_.SetSelectedNode(NULL);
166 EXPECT_EQ(std::string(), GetSelectedNodeTitle());
168 // Select 'c'.
169 tree_.SetSelectedNode(GetNodeByTitle("c"));
170 EXPECT_EQ("c", GetSelectedNodeTitle());
172 // Select 'b1', which should expand 'b'.
173 tree_.SetSelectedNode(GetNodeByTitle("b1"));
174 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
175 EXPECT_EQ("b1", GetSelectedNodeTitle());
178 // Makes sure SetRootShown doesn't blow up.
179 TEST_F(TreeViewTest, HideRoot) {
180 tree_.SetModel(&model_);
181 tree_.SetRootShown(false);
182 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
183 EXPECT_EQ("a", GetSelectedNodeTitle());
184 EXPECT_EQ(3, GetRowCount());
187 // Expands a node and verifies the children are loaded correctly.
188 TEST_F(TreeViewTest, Expand) {
189 tree_.SetModel(&model_);
190 tree_.Expand(GetNodeByTitle("b1"));
191 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
192 EXPECT_EQ("root",GetSelectedNodeTitle());
193 EXPECT_EQ(5, GetRowCount());
196 // Collapes a node and verifies state.
197 TEST_F(TreeViewTest, Collapse) {
198 tree_.SetModel(&model_);
199 tree_.Expand(GetNodeByTitle("b1"));
200 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
201 EXPECT_EQ(5, GetRowCount());
202 tree_.SetSelectedNode(GetNodeByTitle("b1"));
203 EXPECT_EQ("b1", GetSelectedNodeTitle());
204 tree_.Collapse(GetNodeByTitle("b"));
205 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
206 // Selected node should have moved to 'b'
207 EXPECT_EQ("b", GetSelectedNodeTitle());
208 EXPECT_EQ(4, GetRowCount());
211 // Verifies adding nodes works.
212 TEST_F(TreeViewTest, TreeNodesAdded) {
213 tree_.SetModel(&model_);
214 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
215 // Add a node between b and c.
216 Add(model_.GetRoot(), 2, "B");
217 EXPECT_EQ("root [a b B c]", TreeViewContentsAsString());
218 EXPECT_EQ("root", GetSelectedNodeTitle());
219 EXPECT_EQ(5, GetRowCount());
221 // Add a child of b1, which hasn't been loaded and shouldn't do anything.
222 Add(GetNodeByTitle("b1"), 0, "b11");
223 EXPECT_EQ("root [a b B c]", TreeViewContentsAsString());
224 EXPECT_EQ("root", GetSelectedNodeTitle());
225 EXPECT_EQ(5, GetRowCount());
227 // Add a child of b, which isn't expanded yet, so it shouldn't effect
228 // anything.
229 Add(GetNodeByTitle("b"), 1, "b2");
230 EXPECT_EQ("root [a b B c]", TreeViewContentsAsString());
231 EXPECT_EQ("root", GetSelectedNodeTitle());
232 EXPECT_EQ(5, GetRowCount());
234 // Expand b and make sure b2 is there.
235 tree_.Expand(GetNodeByTitle("b"));
236 EXPECT_EQ("root [a b [b1 b2] B c]", TreeViewContentsAsString());
237 EXPECT_EQ("root",GetSelectedNodeTitle());
238 EXPECT_EQ(7, GetRowCount());
241 // Verifies removing nodes works.
242 TEST_F(TreeViewTest, TreeNodesRemoved) {
243 // Add c1 as a child of c and c11 as a child of c1.
244 Add(Add(GetNodeByTitle("c"), 0, "c1"), 0, "c11");
245 tree_.SetModel(&model_);
247 // Remove c11, which shouldn't have any effect on the tree.
248 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
249 EXPECT_EQ("root", GetSelectedNodeTitle());
250 EXPECT_EQ(4, GetRowCount());
252 // Expand b1, then collapse it and remove its only child, b1. This shouldn't
253 // effect the tree.
254 tree_.Expand(GetNodeByTitle("b"));
255 tree_.Collapse(GetNodeByTitle("b"));
256 delete model_.Remove(GetNodeByTitle("b1")->parent(), GetNodeByTitle("b1"));
257 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
258 EXPECT_EQ("root", GetSelectedNodeTitle());
259 EXPECT_EQ(4, GetRowCount());
261 // Remove 'b'.
262 delete model_.Remove(GetNodeByTitle("b")->parent(), GetNodeByTitle("b"));
263 EXPECT_EQ("root [a c]", TreeViewContentsAsString());
264 EXPECT_EQ("root", GetSelectedNodeTitle());
265 EXPECT_EQ(3, GetRowCount());
267 // Remove 'c11', shouldn't visually change anything.
268 delete model_.Remove(GetNodeByTitle("c11")->parent(), GetNodeByTitle("c11"));
269 EXPECT_EQ("root [a c]", TreeViewContentsAsString());
270 EXPECT_EQ("root", GetSelectedNodeTitle());
271 EXPECT_EQ(3, GetRowCount());
273 // Select 'c1', remove 'c' and make sure selection changes.
274 tree_.SetSelectedNode(GetNodeByTitle("c1"));
275 EXPECT_EQ("c1", GetSelectedNodeTitle());
276 delete model_.Remove(GetNodeByTitle("c")->parent(), GetNodeByTitle("c"));
277 EXPECT_EQ("root [a]", TreeViewContentsAsString());
278 EXPECT_EQ("root", GetSelectedNodeTitle());
279 EXPECT_EQ(2, GetRowCount());
281 tree_.SetRootShown(false);
282 // Add 'b' select it and remove it. Because we're not showing the root
283 // selection should change to 'a'.
284 Add(GetNodeByTitle("root"), 1, "b");
285 tree_.SetSelectedNode(GetNodeByTitle("b"));
286 delete model_.Remove(GetNodeByTitle("b")->parent(), GetNodeByTitle("b"));
287 EXPECT_EQ("root [a]", TreeViewContentsAsString());
288 EXPECT_EQ("a", GetSelectedNodeTitle());
289 EXPECT_EQ(1, GetRowCount());
292 // Verifies changing a node title works.
293 TEST_F(TreeViewTest, TreeNodeChanged) {
294 // Add c1 as a child of c and c11 as a child of c1.
295 Add(Add(GetNodeByTitle("c"), 0, "c1"), 0, "c11");
296 tree_.SetModel(&model_);
298 // Change c11, shouldn't do anything.
299 model_.SetTitle(GetNodeByTitle("c11"), ASCIIToUTF16("c11.new"));
300 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
301 EXPECT_EQ("root", GetSelectedNodeTitle());
302 EXPECT_EQ(4, GetRowCount());
304 // Change 'b1', shouldn't do anything.
305 model_.SetTitle(GetNodeByTitle("b1"), ASCIIToUTF16("b1.new"));
306 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
307 EXPECT_EQ("root", GetSelectedNodeTitle());
308 EXPECT_EQ(4, GetRowCount());
310 // Change 'b'.
311 model_.SetTitle(GetNodeByTitle("b"), ASCIIToUTF16("b.new"));
312 EXPECT_EQ("root [a b.new c]", TreeViewContentsAsString());
313 EXPECT_EQ("root", GetSelectedNodeTitle());
314 EXPECT_EQ(4, GetRowCount());
317 // Verifies IncrementSelection() works.
318 TEST_F(TreeViewTest, IncrementSelection) {
319 tree_.SetModel(&model_);
321 IncrementSelection(true);
322 EXPECT_EQ("a", GetSelectedNodeTitle());
323 IncrementSelection(true);
324 EXPECT_EQ("b", GetSelectedNodeTitle());
325 IncrementSelection(true);
326 tree_.Expand(GetNodeByTitle("b"));
327 IncrementSelection(false);
328 EXPECT_EQ("b1", GetSelectedNodeTitle());
329 IncrementSelection(true);
330 EXPECT_EQ("c", GetSelectedNodeTitle());
331 IncrementSelection(true);
332 EXPECT_EQ("c", GetSelectedNodeTitle());
334 tree_.SetRootShown(false);
335 tree_.SetSelectedNode(GetNodeByTitle("a"));
336 EXPECT_EQ("a", GetSelectedNodeTitle());
337 IncrementSelection(false);
338 EXPECT_EQ("a", GetSelectedNodeTitle());
341 // Verifies CollapseOrSelectParent works.
342 TEST_F(TreeViewTest, CollapseOrSelectParent) {
343 tree_.SetModel(&model_);
345 tree_.SetSelectedNode(GetNodeByTitle("root"));
346 CollapseOrSelectParent();
347 EXPECT_EQ("root", TreeViewContentsAsString());
348 EXPECT_EQ("root", GetSelectedNodeTitle());
350 // Hide the root, which should implicitly expand the root.
351 tree_.SetRootShown(false);
352 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
353 EXPECT_EQ("a", GetSelectedNodeTitle());
355 tree_.SetSelectedNode(GetNodeByTitle("b1"));
356 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
357 EXPECT_EQ("b1", GetSelectedNodeTitle());
358 CollapseOrSelectParent();
359 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
360 EXPECT_EQ("b", GetSelectedNodeTitle());
361 CollapseOrSelectParent();
362 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
363 EXPECT_EQ("b", GetSelectedNodeTitle());
366 // Verifies ExpandOrSelectChild works.
367 TEST_F(TreeViewTest, ExpandOrSelectChild) {
368 tree_.SetModel(&model_);
370 tree_.SetSelectedNode(GetNodeByTitle("root"));
371 ExpandOrSelectChild();
372 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
373 EXPECT_EQ("a", GetSelectedNodeTitle());
375 ExpandOrSelectChild();
376 EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
377 EXPECT_EQ("a", GetSelectedNodeTitle());
379 tree_.SetSelectedNode(GetNodeByTitle("b"));
380 ExpandOrSelectChild();
381 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
382 EXPECT_EQ("b", GetSelectedNodeTitle());
383 ExpandOrSelectChild();
384 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
385 EXPECT_EQ("b1", GetSelectedNodeTitle());
386 ExpandOrSelectChild();
387 EXPECT_EQ("root [a b [b1] c]", TreeViewContentsAsString());
388 EXPECT_EQ("b1", GetSelectedNodeTitle());
391 // Verify selection is properly updated on each keystroke.
392 TEST_F(TreeViewTest, SelectOnKeyStroke) {
393 tree_.SetModel(&model_);
394 tree_.ExpandAll(model_.GetRoot());
395 selector()->InsertText(ASCIIToUTF16("b"));
396 EXPECT_EQ("b", GetSelectedNodeTitle());
397 selector()->InsertText(ASCIIToUTF16("1"));
398 EXPECT_EQ("b1", GetSelectedNodeTitle());
400 // Invoke OnViewBlur() to reset time.
401 selector()->OnViewBlur();
402 selector()->InsertText(ASCIIToUTF16("z"));
403 EXPECT_EQ("b1", GetSelectedNodeTitle());
405 selector()->OnViewBlur();
406 selector()->InsertText(ASCIIToUTF16("a"));
407 EXPECT_EQ("a", GetSelectedNodeTitle());
410 // Verifies edits are committed when focus is lost.
411 TEST_F(TreeViewTest, CommitOnFocusLost) {
412 tree_.SetModel(&model_);
414 tree_.SetSelectedNode(GetNodeByTitle("root"));
415 ExpandOrSelectChild();
416 tree_.SetEditable(true);
417 tree_.StartEditing(GetNodeByTitle("a"));
418 tree_.editor()->SetText(ASCIIToUTF16("a changed"));
419 tree_.OnDidChangeFocus(NULL, NULL);
420 EXPECT_TRUE(GetNodeByTitle("a changed") != NULL);
423 } // namespace views