Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / mojo / services / public / cpp / view_manager / tests / view_manager_unittest.cc
1 // Copyright 2014 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 "mojo/services/public/cpp/view_manager/view_manager.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h"
10 #include "mojo/services/public/cpp/view_manager/util.h"
11 #include "mojo/services/public/cpp/view_manager/view_tree_node_observer.h"
12 #include "mojo/shell/shell_test_helper.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace mojo {
16 namespace services {
17 namespace view_manager {
18
19 base::RunLoop* current_run_loop = NULL;
20
21 void DoRunLoop() {
22   base::RunLoop run_loop;
23   current_run_loop = &run_loop;
24   current_run_loop->Run();
25   current_run_loop = NULL;
26 }
27
28 void QuitRunLoop() {
29   current_run_loop->Quit();
30 }
31
32 // ViewManager -----------------------------------------------------------------
33
34 // These tests model synchronization of two peer connections to the view manager
35 // service, that are given access to some root node.
36
37 class ViewManagerTest : public testing::Test {
38  public:
39   ViewManagerTest() : commit_count_(0) {}
40
41  protected:
42   ViewManager* view_manager_1() { return view_manager_1_.get(); }
43   ViewManager* view_manager_2() { return view_manager_2_.get(); }
44
45   ViewTreeNode* CreateNodeInParent(ViewTreeNode* parent) {
46     ViewManager* parent_manager = ViewTreeNodePrivate(parent).view_manager();
47     ViewTreeNode* node = ViewTreeNode::Create(parent_manager);
48     parent->AddChild(node);
49     return node;
50   }
51
52   void DestroyViewManager1() {
53     view_manager_1_.reset();
54   }
55
56  private:
57   // Overridden from testing::Test:
58   virtual void SetUp() OVERRIDE {
59     test_helper_.Init();
60     view_manager_1_.reset(new ViewManager(test_helper_.shell()));
61     view_manager_2_.reset(new ViewManager(test_helper_.shell()));
62     view_manager_1_->Init();
63     view_manager_2_->Init();
64   }
65
66   base::MessageLoop loop_;
67   shell::ShellTestHelper test_helper_;
68   scoped_ptr<ViewManager> view_manager_1_;
69   scoped_ptr<ViewManager> view_manager_2_;
70   int commit_count_;
71
72   DISALLOW_COPY_AND_ASSIGN(ViewManagerTest);
73 };
74
75 // Base class for helpers that quit the current runloop after a specific tree
76 // change is observed by a view manager.
77 class TreeObserverBase : public ViewTreeNodeObserver {
78  public:
79   explicit TreeObserverBase(ViewManager* view_manager)
80       : view_manager_(view_manager) {
81     view_manager_->tree()->AddObserver(this);
82   }
83   virtual ~TreeObserverBase() {
84     view_manager_->tree()->RemoveObserver(this);
85   }
86
87  protected:
88   virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) = 0;
89
90   ViewManager* view_manager() { return view_manager_; }
91
92  private:
93   // Overridden from ViewTreeNodeObserver:
94   virtual void OnTreeChange(const TreeChangeParams& params) OVERRIDE {
95     if (ShouldQuitRunLoop(params))
96       QuitRunLoop();
97   }
98
99   ViewManager* view_manager_;
100   DISALLOW_COPY_AND_ASSIGN(TreeObserverBase);
101 };
102
103 // Spins a runloop until the tree beginning at |root| has |tree_size| nodes
104 // (including |root|).
105 class TreeSizeMatchesWaiter : public TreeObserverBase {
106  public:
107   TreeSizeMatchesWaiter(ViewManager* view_manager, size_t tree_size)
108       : TreeObserverBase(view_manager),
109         tree_size_(tree_size) {
110     DoRunLoop();
111   }
112   virtual ~TreeSizeMatchesWaiter() {}
113
114  private:
115   // Overridden from TreeObserverBase:
116   virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE {
117     if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED)
118       return false;
119     return CountNodes(view_manager()->tree()) == tree_size_;
120   }
121
122   size_t CountNodes(ViewTreeNode* node) const {
123     size_t count = 1;
124     ViewTreeNode::Children::const_iterator it = node->children().begin();
125     for (; it != node->children().end(); ++it)
126       count += CountNodes(*it);
127     return count;
128   }
129
130   size_t tree_size_;
131   DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesWaiter);
132 };
133
134
135 class HierarchyChanged_NodeCreatedObserver : public TreeObserverBase {
136  public:
137   explicit HierarchyChanged_NodeCreatedObserver(ViewManager* view_manager)
138       : TreeObserverBase(view_manager) {}
139   virtual ~HierarchyChanged_NodeCreatedObserver() {}
140
141  private:
142   // Overridden from TreeObserverBase:
143   virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE {
144     if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED)
145       return false;
146     return params.receiver == view_manager()->tree() &&
147         !params.old_parent &&
148         params.new_parent == view_manager()->tree();
149   }
150
151   DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeCreatedObserver);
152 };
153
154 TEST_F(ViewManagerTest, HierarchyChanged_NodeCreated) {
155   HierarchyChanged_NodeCreatedObserver observer(view_manager_2());
156   ViewTreeNode* node1 = ViewTreeNode::Create(view_manager_1());
157   view_manager_1()->tree()->AddChild(node1);
158   DoRunLoop();
159
160   EXPECT_EQ(view_manager_2()->tree()->children().front()->id(), node1->id());
161 }
162
163 // Quits the current runloop when the root is notified about a node moved from
164 // |old_parent_id| to |new_parent_id|.
165 class HierarchyChanged_NodeMovedObserver : public TreeObserverBase {
166  public:
167   HierarchyChanged_NodeMovedObserver(ViewManager* view_manager,
168                                      TransportNodeId old_parent_id,
169                                      TransportNodeId new_parent_id)
170       : TreeObserverBase(view_manager),
171         old_parent_id_(old_parent_id),
172         new_parent_id_(new_parent_id) {}
173   virtual ~HierarchyChanged_NodeMovedObserver() {}
174
175  private:
176   // Overridden from TreeObserverBase:
177   virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE {
178     if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED)
179       return false;
180     return params.receiver == view_manager()->tree() &&
181         params.old_parent->id() == old_parent_id_&&
182         params.new_parent->id() == new_parent_id_;
183   }
184
185   TransportNodeId old_parent_id_;
186   TransportNodeId new_parent_id_;
187
188   DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeMovedObserver);
189 };
190
191 TEST_F(ViewManagerTest, HierarchyChanged_NodeMoved) {
192   ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
193   ViewTreeNode* node2 = CreateNodeInParent(view_manager_1()->tree());
194   ViewTreeNode* node21 = CreateNodeInParent(node2);
195   TreeSizeMatchesWaiter waiter(view_manager_2(), 4);
196
197   HierarchyChanged_NodeMovedObserver observer(view_manager_2(),
198                                               node2->id(),
199                                               node1->id());
200
201   node1->AddChild(node21);
202   DoRunLoop();
203
204   ViewTreeNode* tree2 = view_manager_2()->tree();
205
206   EXPECT_EQ(tree2->children().size(), 2u);
207   ViewTreeNode* tree2_node1 = tree2->GetChildById(node1->id());
208   EXPECT_EQ(tree2_node1->children().size(), 1u);
209   ViewTreeNode* tree2_node2 = tree2->GetChildById(node2->id());
210   EXPECT_TRUE(tree2_node2->children().empty());
211   ViewTreeNode* tree2_node21 = tree2->GetChildById(node21->id());
212   EXPECT_EQ(tree2_node21->parent(), tree2_node1);
213 }
214
215 class HierarchyChanged_NodeRemovedObserver : public TreeObserverBase {
216  public:
217   HierarchyChanged_NodeRemovedObserver(ViewManager* view_manager)
218       : TreeObserverBase(view_manager) {}
219   virtual ~HierarchyChanged_NodeRemovedObserver() {}
220
221  private:
222   // Overridden from TreeObserverBase:
223   virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE {
224     if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGING)
225       return false;
226     return params.receiver == view_manager()->tree() &&
227         params.old_parent->id() == params.receiver->id() &&
228         params.new_parent == 0;
229   }
230
231   DISALLOW_COPY_AND_ASSIGN(HierarchyChanged_NodeRemovedObserver);
232 };
233
234 TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) {
235   ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
236   TreeSizeMatchesWaiter waiter(view_manager_2(), 2);
237
238   HierarchyChanged_NodeRemovedObserver observer(view_manager_2());
239
240   view_manager_1()->tree()->RemoveChild(node1);
241   DoRunLoop();
242
243   ViewTreeNode* tree2 = view_manager_2()->tree();
244
245   EXPECT_TRUE(tree2->children().empty());
246 }
247
248 class NodeDestroyed_Waiter : public ViewTreeNodeObserver {
249  public:
250   NodeDestroyed_Waiter(ViewManager* view_manager, TransportNodeId id)
251       : id_(id),
252         view_manager_(view_manager) {
253     view_manager_->GetNodeById(id)->AddObserver(this);
254     DoRunLoop();
255   }
256   virtual ~NodeDestroyed_Waiter() {
257   }
258
259  private:
260   // Overridden from TreeObserverBase:
261   virtual void OnNodeDestroy(ViewTreeNode* node,
262                              DispositionChangePhase phase) OVERRIDE {
263     if (phase != DISPOSITION_CHANGED)
264       return;
265     if (node->id() == id_)
266       QuitRunLoop();
267   }
268
269   TransportNodeId id_;
270   ViewManager* view_manager_;
271
272   DISALLOW_COPY_AND_ASSIGN(NodeDestroyed_Waiter);
273 };
274
275 TEST_F(ViewManagerTest, NodeDestroyed) {
276   ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
277   TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
278
279   // |node1| will be deleted after calling Destroy() below.
280   TransportNodeId id = node1->id();
281   node1->Destroy();
282   NodeDestroyed_Waiter destroyed_waiter(view_manager_2(), id);
283
284   EXPECT_TRUE(view_manager_2()->tree()->children().empty());
285 }
286
287 TEST_F(ViewManagerTest, ViewManagerDestroyed) {
288   ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
289   TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
290
291   TransportNodeId id = node1->id();
292   DestroyViewManager1();
293   NodeDestroyed_Waiter destroyed_waiter(view_manager_2(), id);
294
295   // tree() should still be valid, since it's owned by neither connection.
296   EXPECT_TRUE(view_manager_2()->tree()->children().empty());
297 }
298
299 }  // namespace view_manager
300 }  // namespace services
301 }  // namespace mojo