- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / frame_host / frame_tree_unittest.cc
1 // Copyright 2013 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.
4
5 #include "content/browser/frame_host/frame_tree.h"
6
7 #include "base/run_loop.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "content/browser/frame_host/render_frame_host_impl.h"
10 #include "content/browser/renderer_host/render_view_host_impl.h"
11 #include "content/public/test/mock_render_process_host.h"
12 #include "content/public/test/test_browser_context.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "content/public/test/test_renderer_host.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace content {
18 namespace {
19
20 class FrameTreeTest : public RenderViewHostTestHarness {
21  protected:
22   // Prints a FrameTree, for easy assertions of the tree hierarchy.
23   std::string GetTreeState(FrameTree* frame_tree) {
24     std::string result;
25     AppendTreeNodeState(frame_tree->GetRootForTesting(), &result);
26     return result;
27   }
28
29  private:
30   void AppendTreeNodeState(FrameTreeNode* node, std::string* result) {
31     result->append(base::Int64ToString(node->frame_id()));
32     if (!node->frame_name().empty()) {
33       result->append(" '");
34       result->append(node->frame_name());
35       result->append("'");
36     }
37     result->append(": [");
38     const char* separator = "";
39     for (size_t i = 0; i < node->child_count(); i++) {
40       result->append(separator);
41       AppendTreeNodeState(node->child_at(i), result);
42       separator = ", ";
43     }
44     result->append("]");
45   }
46 };
47
48 // The root node never changes during navigation even though its
49 // RenderFrameHost does.
50 //  - Swapping main frame doesn't change root node.
51 //  - Swapping back to NULL doesn't crash (easier tear-down for interstitials).
52 //  - Main frame does not own RenderFrameHost.
53 TEST_F(FrameTreeTest, RootNode) {
54   FrameTree frame_tree;
55
56   // Initial state has empty node.
57   FrameTreeNode* root = frame_tree.GetRootForTesting();
58   ASSERT_TRUE(root);
59   EXPECT_FALSE(frame_tree.GetMainFrame());
60
61   // Swap in main frame.
62   RenderFrameHostImpl* dummy = reinterpret_cast<RenderFrameHostImpl*>(0x1);
63   frame_tree.SwapMainFrame(dummy);
64   EXPECT_EQ(root, frame_tree.GetRootForTesting());
65   EXPECT_EQ(dummy, frame_tree.GetMainFrame());
66
67   // Move back to NULL.
68   frame_tree.SwapMainFrame(NULL);
69   EXPECT_EQ(root, frame_tree.GetRootForTesting());
70   EXPECT_FALSE(frame_tree.GetMainFrame());
71
72   // Move back to an invalid pointer, let the FrameTree go out of scope. Test
73   // should not crash because the main frame isn't owned.
74   frame_tree.SwapMainFrame(dummy);
75 }
76
77 // Test that swapping the main frame resets the renderer-assigned frame id.
78 //  - On creation, frame id is unassigned.
79 //  - After a swap, frame id is unassigned.
80 TEST_F(FrameTreeTest, FirstNavigationAfterSwap) {
81   FrameTree frame_tree;
82
83   EXPECT_TRUE(frame_tree.IsFirstNavigationAfterSwap());
84   EXPECT_EQ(FrameTreeNode::kInvalidFrameId,
85             frame_tree.GetRootForTesting()->frame_id());
86   frame_tree.OnFirstNavigationAfterSwap(1);
87   EXPECT_FALSE(frame_tree.IsFirstNavigationAfterSwap());
88   EXPECT_EQ(1, frame_tree.GetRootForTesting()->frame_id());
89
90   frame_tree.SwapMainFrame(NULL);
91   EXPECT_TRUE(frame_tree.IsFirstNavigationAfterSwap());
92   EXPECT_EQ(FrameTreeNode::kInvalidFrameId,
93             frame_tree.GetRootForTesting()->frame_id());
94 }
95
96 // Exercise tree manipulation routines.
97 //  - Add a series of nodes and verify tree structure.
98 //  - Remove a series of nodes and verify tree structure.
99 TEST_F(FrameTreeTest, Shape) {
100   FrameTree frame_tree;
101   std::string no_children_node("no children node");
102   std::string deep_subtree("node with deep subtree");
103
104   // Ensure the top-level node of the FrameTree is initialized by simulating a
105   // main frame swap here.
106   RenderFrameHostImpl render_frame_host(static_cast<RenderViewHostImpl*>(rvh()),
107                                         &frame_tree,
108                                         process()->GetNextRoutingID(), false);
109   frame_tree.SwapMainFrame(&render_frame_host);
110   frame_tree.OnFirstNavigationAfterSwap(5);
111
112   ASSERT_EQ("5: []", GetTreeState(&frame_tree));
113
114   // Simulate attaching a series of frames to build the frame tree.
115   frame_tree.AddFrame(process()->GetNextRoutingID(), 5, 14, std::string());
116   frame_tree.AddFrame(process()->GetNextRoutingID(), 5, 15, std::string());
117   frame_tree.AddFrame(process()->GetNextRoutingID(), 5, 16, std::string());
118
119   frame_tree.AddFrame(process()->GetNextRoutingID(), 14, 244, std::string());
120   frame_tree.AddFrame(process()->GetNextRoutingID(), 15, 255, no_children_node);
121   frame_tree.AddFrame(process()->GetNextRoutingID(), 14, 245, std::string());
122
123   ASSERT_EQ("5: [14: [244: [], 245: []], "
124                 "15: [255 'no children node': []], "
125                 "16: []]",
126             GetTreeState(&frame_tree));
127
128   frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 264, std::string());
129   frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 265, std::string());
130   frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 266, std::string());
131   frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 267, deep_subtree);
132   frame_tree.AddFrame(process()->GetNextRoutingID(), 16, 268, std::string());
133
134   frame_tree.AddFrame(process()->GetNextRoutingID(), 267, 365, std::string());
135   frame_tree.AddFrame(process()->GetNextRoutingID(), 365, 455, std::string());
136   frame_tree.AddFrame(process()->GetNextRoutingID(), 455, 555, std::string());
137   frame_tree.AddFrame(process()->GetNextRoutingID(), 555, 655, std::string());
138
139   // Now that's it's fully built, verify the tree structure is as expected.
140   ASSERT_EQ("5: [14: [244: [], 245: []], "
141                 "15: [255 'no children node': []], "
142                 "16: [264: [], 265: [], 266: [], "
143                      "267 'node with deep subtree': "
144                          "[365: [455: [555: [655: []]]]], 268: []]]",
145             GetTreeState(&frame_tree));
146
147   // Test removing of nodes.
148   frame_tree.RemoveFrame(555, 655);
149   ASSERT_EQ("5: [14: [244: [], 245: []], "
150                 "15: [255 'no children node': []], "
151                 "16: [264: [], 265: [], 266: [], "
152                      "267 'node with deep subtree': "
153                          "[365: [455: [555: []]]], 268: []]]",
154             GetTreeState(&frame_tree));
155
156   frame_tree.RemoveFrame(16, 265);
157   ASSERT_EQ("5: [14: [244: [], 245: []], "
158                 "15: [255 'no children node': []], "
159                 "16: [264: [], 266: [], "
160                      "267 'node with deep subtree': "
161                          "[365: [455: [555: []]]], 268: []]]",
162             GetTreeState(&frame_tree));
163
164   frame_tree.RemoveFrame(5, 15);
165   ASSERT_EQ("5: [14: [244: [], 245: []], "
166                 "16: [264: [], 266: [], "
167                      "267 'node with deep subtree': "
168                          "[365: [455: [555: []]]], 268: []]]",
169             GetTreeState(&frame_tree));
170 }
171
172 }  // namespace
173 }  // namespace content