| Index: mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc
|
| diff --git a/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc b/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc
|
| index fd57dd53137f517da7fa35e821278fe33f35b755..f86820a4d6440cac66f8508ea920e2082cadb0b2 100644
|
| --- a/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc
|
| +++ b/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc
|
| @@ -6,6 +6,8 @@
|
|
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| +#include "mojo/services/public/cpp/view_manager/lib/view_manager_private.h"
|
| +#include "mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h"
|
| #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h"
|
| #include "mojo/services/public/cpp/view_manager/util.h"
|
| #include "mojo/services/public/cpp/view_manager/view.h"
|
| @@ -30,6 +32,159 @@ void QuitRunLoop() {
|
| current_run_loop->Quit();
|
| }
|
|
|
| +void QuitRunLoopOnChangesAcked() {
|
| + QuitRunLoop();
|
| +}
|
| +
|
| +void WaitForAllChangesToBeAcked(ViewManager* manager) {
|
| + ViewManagerPrivate(manager).synchronizer()->set_changes_acked_callback(
|
| + base::Bind(&QuitRunLoopOnChangesAcked));
|
| + DoRunLoop();
|
| + ViewManagerPrivate(manager).synchronizer()->ClearChangesAckedCallback();
|
| +}
|
| +
|
| +class ActiveViewChangedObserver : public ViewTreeNodeObserver {
|
| + public:
|
| + explicit ActiveViewChangedObserver(ViewTreeNode* node)
|
| + : node_(node) {}
|
| + virtual ~ActiveViewChangedObserver() {}
|
| +
|
| + private:
|
| + // Overridden from ViewTreeNodeObserver:
|
| + virtual void OnNodeActiveViewChange(ViewTreeNode* node,
|
| + View* old_view,
|
| + View* new_view,
|
| + DispositionChangePhase phase) OVERRIDE {
|
| + DCHECK_EQ(node, node_);
|
| + QuitRunLoop();
|
| + }
|
| +
|
| + ViewTreeNode* node_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ActiveViewChangedObserver);
|
| +};
|
| +
|
| +// Waits until the active view id of the supplied node changes.
|
| +void WaitForActiveViewToChange(ViewTreeNode* node) {
|
| + ActiveViewChangedObserver observer(node);
|
| + node->AddObserver(&observer);
|
| + DoRunLoop();
|
| + node->RemoveObserver(&observer);
|
| +}
|
| +
|
| +// Spins a runloop until the tree beginning at |root| has |tree_size| nodes
|
| +// (including |root|).
|
| +class TreeSizeMatchesObserver : public ViewTreeNodeObserver {
|
| + public:
|
| + TreeSizeMatchesObserver(ViewTreeNode* tree, size_t tree_size)
|
| + : tree_(tree),
|
| + tree_size_(tree_size) {}
|
| + virtual ~TreeSizeMatchesObserver() {}
|
| +
|
| + bool IsTreeCorrectSize() {
|
| + return CountNodes(tree_) == tree_size_;
|
| + }
|
| +
|
| + private:
|
| + // Overridden from ViewTreeNodeObserver:
|
| + virtual void OnTreeChange(const TreeChangeParams& params) OVERRIDE {
|
| + if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED)
|
| + return;
|
| + if (IsTreeCorrectSize())
|
| + QuitRunLoop();
|
| + }
|
| +
|
| + size_t CountNodes(const ViewTreeNode* node) const {
|
| + size_t count = 1;
|
| + ViewTreeNode::Children::const_iterator it = node->children().begin();
|
| + for (; it != node->children().end(); ++it)
|
| + count += CountNodes(*it);
|
| + return count;
|
| + }
|
| +
|
| + ViewTreeNode* tree_;
|
| + size_t tree_size_;
|
| + DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver);
|
| +};
|
| +
|
| +void WaitForTreeSizeToMatch(ViewTreeNode* node, size_t tree_size) {
|
| + TreeSizeMatchesObserver observer(node, tree_size);
|
| + if (observer.IsTreeCorrectSize())
|
| + return;
|
| + node->AddObserver(&observer);
|
| + DoRunLoop();
|
| + node->RemoveObserver(&observer);
|
| +}
|
| +
|
| +
|
| +// Utility class that waits for the destruction of some number of nodes and
|
| +// views.
|
| +class DestructionObserver : public ViewTreeNodeObserver,
|
| + public ViewObserver {
|
| + public:
|
| + // |nodes| or |views| can be NULL.
|
| + DestructionObserver(std::set<TransportNodeId>* nodes,
|
| + std::set<TransportViewId>* views)
|
| + : nodes_(nodes),
|
| + views_(views) {}
|
| +
|
| + private:
|
| + // Overridden from ViewTreeNodeObserver:
|
| + virtual void OnNodeDestroy(
|
| + ViewTreeNode* node,
|
| + ViewTreeNodeObserver::DispositionChangePhase phase) OVERRIDE {
|
| + if (phase != ViewTreeNodeObserver::DISPOSITION_CHANGED)
|
| + return;
|
| + std::set<TransportNodeId>::const_iterator it = nodes_->find(node->id());
|
| + if (it != nodes_->end())
|
| + nodes_->erase(it);
|
| + if (CanQuit())
|
| + QuitRunLoop();
|
| + }
|
| +
|
| + // Overridden from ViewObserver:
|
| + virtual void OnViewDestroy(
|
| + View* view,
|
| + ViewObserver::DispositionChangePhase phase) OVERRIDE {
|
| + if (phase != ViewObserver::DISPOSITION_CHANGED)
|
| + return;
|
| + std::set<TransportViewId>::const_iterator it = views_->find(view->id());
|
| + if (it != views_->end())
|
| + views_->erase(it);
|
| + if (CanQuit())
|
| + QuitRunLoop();
|
| + }
|
| +
|
| + bool CanQuit() {
|
| + return (!nodes_ || nodes_->empty()) && (!views_ || views_->empty());
|
| + }
|
| +
|
| + std::set<TransportNodeId>* nodes_;
|
| + std::set<TransportViewId>* views_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DestructionObserver);
|
| +};
|
| +
|
| +void WaitForDestruction(ViewManager* view_manager,
|
| + std::set<TransportNodeId>* nodes,
|
| + std::set<TransportViewId>* views) {
|
| + DestructionObserver observer(nodes, views);
|
| + DCHECK(nodes || views);
|
| + if (nodes) {
|
| + for (std::set<TransportNodeId>::const_iterator it = nodes->begin();
|
| + it != nodes->end(); ++it) {
|
| + view_manager->GetNodeById(*it)->AddObserver(&observer);
|
| + }
|
| + }
|
| + if (views) {
|
| + for (std::set<TransportViewId>::const_iterator it = views->begin();
|
| + it != views->end(); ++it) {
|
| + view_manager->GetViewById(*it)->AddObserver(&observer);
|
| + }
|
| + }
|
| + DoRunLoop();
|
| +}
|
| +
|
| // ViewManager -----------------------------------------------------------------
|
|
|
| // These tests model synchronization of two peer connections to the view manager
|
| @@ -101,38 +256,6 @@ class TreeObserverBase : public ViewTreeNodeObserver {
|
| DISALLOW_COPY_AND_ASSIGN(TreeObserverBase);
|
| };
|
|
|
| -// Spins a runloop until the tree beginning at |root| has |tree_size| nodes
|
| -// (including |root|).
|
| -class TreeSizeMatchesWaiter : public TreeObserverBase {
|
| - public:
|
| - TreeSizeMatchesWaiter(ViewManager* view_manager, size_t tree_size)
|
| - : TreeObserverBase(view_manager),
|
| - tree_size_(tree_size) {
|
| - DoRunLoop();
|
| - }
|
| - virtual ~TreeSizeMatchesWaiter() {}
|
| -
|
| - private:
|
| - // Overridden from TreeObserverBase:
|
| - virtual bool ShouldQuitRunLoop(const TreeChangeParams& params) OVERRIDE {
|
| - if (params.phase != ViewTreeNodeObserver::DISPOSITION_CHANGED)
|
| - return false;
|
| - return CountNodes(view_manager()->tree()) == tree_size_;
|
| - }
|
| -
|
| - size_t CountNodes(ViewTreeNode* node) const {
|
| - size_t count = 1;
|
| - ViewTreeNode::Children::const_iterator it = node->children().begin();
|
| - for (; it != node->children().end(); ++it)
|
| - count += CountNodes(*it);
|
| - return count;
|
| - }
|
| -
|
| - size_t tree_size_;
|
| - DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesWaiter);
|
| -};
|
| -
|
| -
|
| class HierarchyChanged_NodeCreatedObserver : public TreeObserverBase {
|
| public:
|
| explicit HierarchyChanged_NodeCreatedObserver(ViewManager* view_manager)
|
| @@ -193,7 +316,7 @@ TEST_F(ViewManagerTest, HierarchyChanged_NodeMoved) {
|
| ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
|
| ViewTreeNode* node2 = CreateNodeInParent(view_manager_1()->tree());
|
| ViewTreeNode* node21 = CreateNodeInParent(node2);
|
| - TreeSizeMatchesWaiter waiter(view_manager_2(), 4);
|
| + WaitForTreeSizeToMatch(view_manager_2()->tree(), 4);
|
|
|
| HierarchyChanged_NodeMovedObserver observer(view_manager_2(),
|
| node2->id(),
|
| @@ -234,7 +357,7 @@ class HierarchyChanged_NodeRemovedObserver : public TreeObserverBase {
|
|
|
| TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) {
|
| ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
|
| - TreeSizeMatchesWaiter waiter(view_manager_2(), 2);
|
| + WaitForTreeSizeToMatch(view_manager_2()->tree(), 2);
|
|
|
| HierarchyChanged_NodeRemovedObserver observer(view_manager_2());
|
|
|
| @@ -246,73 +369,9 @@ TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) {
|
| EXPECT_TRUE(tree2->children().empty());
|
| }
|
|
|
| -// Utility class that waits for the destruction of some number of nodes and
|
| -// views.
|
| -class DestructionWaiter : public ViewTreeNodeObserver,
|
| - public ViewObserver {
|
| - public:
|
| - // |nodes| or |views| can be NULL.
|
| - DestructionWaiter(ViewManager* view_manager,
|
| - std::set<TransportNodeId>* nodes,
|
| - std::set<TransportViewId>* views)
|
| - : nodes_(nodes),
|
| - views_(views) {
|
| - DCHECK(nodes || views);
|
| - if (nodes) {
|
| - for (std::set<TransportNodeId>::const_iterator it = nodes->begin();
|
| - it != nodes->end(); ++it) {
|
| - view_manager->GetNodeById(*it)->AddObserver(this);
|
| - }
|
| - }
|
| - if (views) {
|
| - for (std::set<TransportViewId>::const_iterator it = views->begin();
|
| - it != views->end(); ++it) {
|
| - view_manager->GetViewById(*it)->AddObserver(this);
|
| - }
|
| - }
|
| - DoRunLoop();
|
| - }
|
| -
|
| - private:
|
| - // Overridden from ViewTreeNodeObserver:
|
| - virtual void OnNodeDestroy(
|
| - ViewTreeNode* node,
|
| - ViewTreeNodeObserver::DispositionChangePhase phase) OVERRIDE {
|
| - if (phase != ViewTreeNodeObserver::DISPOSITION_CHANGED)
|
| - return;
|
| - std::set<TransportNodeId>::const_iterator it = nodes_->find(node->id());
|
| - if (it != nodes_->end())
|
| - nodes_->erase(it);
|
| - if (CanQuit())
|
| - QuitRunLoop();
|
| - }
|
| -
|
| - // Overridden from ViewObserver:
|
| - virtual void OnViewDestroy(
|
| - View* view,
|
| - ViewObserver::DispositionChangePhase phase) OVERRIDE {
|
| - if (phase != ViewObserver::DISPOSITION_CHANGED)
|
| - return;
|
| - std::set<TransportViewId>::const_iterator it = views_->find(view->id());
|
| - if (it != views_->end())
|
| - views_->erase(it);
|
| - if (CanQuit())
|
| - QuitRunLoop();
|
| - }
|
| -
|
| - bool CanQuit() {
|
| - return (!nodes_ || nodes_->empty()) && (!views_ || views_->empty());
|
| - }
|
| -
|
| - std::set<TransportNodeId>* nodes_;
|
| - std::set<TransportViewId>* views_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(DestructionWaiter);
|
| -};
|
| -
|
| TEST_F(ViewManagerTest, NodeDestroyed) {
|
| ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
|
| - TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
|
| + WaitForTreeSizeToMatch(view_manager_2()->tree(), 2);
|
|
|
| // |node1| will be deleted after calling Destroy() below.
|
| TransportNodeId id = node1->id();
|
| @@ -320,7 +379,7 @@ TEST_F(ViewManagerTest, NodeDestroyed) {
|
|
|
| std::set<TransportNodeId> nodes;
|
| nodes.insert(id);
|
| - DestructionWaiter destroyed_waiter(view_manager_2(), &nodes, NULL);
|
| + WaitForDestruction(view_manager_2(), &nodes, NULL);
|
|
|
| EXPECT_TRUE(view_manager_2()->tree()->children().empty());
|
| EXPECT_EQ(NULL, view_manager_2()->GetNodeById(id));
|
| @@ -328,74 +387,47 @@ TEST_F(ViewManagerTest, NodeDestroyed) {
|
|
|
| TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNode) {
|
| ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
|
| - TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
|
| + WaitForTreeSizeToMatch(view_manager_2()->tree(), 2);
|
|
|
| TransportNodeId id = node1->id();
|
| DestroyViewManager1();
|
| std::set<TransportNodeId> nodes;
|
| nodes.insert(id);
|
| - DestructionWaiter destroyed_waiter(view_manager_2(), &nodes, NULL);
|
| + WaitForDestruction(view_manager_2(), &nodes, NULL);
|
|
|
| // tree() should still be valid, since it's owned by neither connection.
|
| EXPECT_TRUE(view_manager_2()->tree()->children().empty());
|
| }
|
|
|
| -// Waits until the active view id of the supplied node changes.
|
| -class ActiveViewChangedWaiter : public ViewTreeNodeObserver {
|
| - public:
|
| - explicit ActiveViewChangedWaiter(ViewTreeNode* node)
|
| - : node_(node) {
|
| - node_->AddObserver(this);
|
| - DoRunLoop();
|
| - }
|
| - virtual ~ActiveViewChangedWaiter() {
|
| - node_->RemoveObserver(this);
|
| - }
|
| -
|
| - private:
|
| - // Overridden from ViewTreeNodeObserver:
|
| - virtual void OnNodeActiveViewChange(ViewTreeNode* node,
|
| - View* old_view,
|
| - View* new_view,
|
| - DispositionChangePhase phase) OVERRIDE {
|
| - DCHECK_EQ(node, node_);
|
| - QuitRunLoop();
|
| - }
|
| -
|
| - ViewTreeNode* node_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(ActiveViewChangedWaiter);
|
| -};
|
| -
|
| TEST_F(ViewManagerTest, SetActiveView) {
|
| ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
|
| - TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
|
| + WaitForTreeSizeToMatch(view_manager_2()->tree(), 2);
|
|
|
| View* view1 = View::Create(view_manager_1());
|
| node1->SetActiveView(view1);
|
|
|
| ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id());
|
| - ActiveViewChangedWaiter waiter(node1_2);
|
| + WaitForActiveViewToChange(node1_2);
|
|
|
| EXPECT_EQ(node1_2->active_view()->id(), view1->id());
|
| }
|
|
|
| TEST_F(ViewManagerTest, DestroyView) {
|
| ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
|
| - TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
|
| + WaitForTreeSizeToMatch(view_manager_2()->tree(), 2);
|
|
|
| View* view1 = View::Create(view_manager_1());
|
| node1->SetActiveView(view1);
|
|
|
| ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id());
|
| - ActiveViewChangedWaiter active_view_waiter(node1_2);
|
| + WaitForActiveViewToChange(node1_2);
|
|
|
| TransportViewId view1_id = view1->id();
|
| view1->Destroy();
|
|
|
| std::set<TransportViewId> views;
|
| views.insert(view1_id);
|
| - DestructionWaiter destruction_waiter(view_manager_2(), NULL, &views);
|
| + WaitForDestruction(view_manager_2(), NULL, &views);
|
| EXPECT_EQ(NULL, node1_2->active_view());
|
| EXPECT_EQ(NULL, view_manager_2()->GetViewById(view1_id));
|
| }
|
| @@ -404,15 +436,13 @@ TEST_F(ViewManagerTest, DestroyView) {
|
| // node and view disappearing from all connections that see them.
|
| TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNodeAndView) {
|
| ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
|
| - TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
|
| + WaitForTreeSizeToMatch(view_manager_2()->tree(), 2);
|
|
|
| View* view1 = View::Create(view_manager_1());
|
| node1->SetActiveView(view1);
|
|
|
| ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id());
|
| - {
|
| - ActiveViewChangedWaiter active_view_waiter(node1_2);
|
| - }
|
| + WaitForActiveViewToChange(node1_2);
|
|
|
| TransportNodeId node1_id = node1->id();
|
| TransportViewId view1_id = view1->id();
|
| @@ -422,9 +452,7 @@ TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNodeAndView) {
|
| observed_nodes.insert(node1_id);
|
| std::set<TransportViewId> observed_views;
|
| observed_views.insert(view1_id);
|
| - DestructionWaiter destruction_waiter(view_manager_2(),
|
| - &observed_nodes,
|
| - &observed_views);
|
| + WaitForDestruction(view_manager_2(), &observed_nodes, &observed_views);
|
|
|
| // tree() should still be valid, since it's owned by neither connection.
|
| EXPECT_TRUE(view_manager_2()->tree()->children().empty());
|
| @@ -441,15 +469,12 @@ TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNodeAndView) {
|
| TEST_F(ViewManagerTest,
|
| ViewManagerDestroyed_CleanupNodeAndViewFromDifferentConnections) {
|
| ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
|
| - TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
|
| + WaitForTreeSizeToMatch(view_manager_2()->tree(), 2);
|
|
|
| View* view1_2 = View::Create(view_manager_2());
|
| ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id());
|
| node1_2->SetActiveView(view1_2);
|
| -
|
| - {
|
| - ActiveViewChangedWaiter active_view_waiter(node1);
|
| - }
|
| + WaitForActiveViewToChange(node1);
|
|
|
| TransportNodeId node1_id = node1->id();
|
| TransportViewId view1_2_id = view1_2->id();
|
| @@ -457,7 +482,7 @@ TEST_F(ViewManagerTest,
|
| DestroyViewManager1();
|
| std::set<TransportNodeId> nodes;
|
| nodes.insert(node1_id);
|
| - DestructionWaiter destruction_waiter(view_manager_2(), &nodes, NULL);
|
| + WaitForDestruction(view_manager_2(), &nodes, NULL);
|
|
|
| // tree() should still be valid, since it's owned by neither connection.
|
| EXPECT_TRUE(view_manager_2()->tree()->children().empty());
|
| @@ -476,11 +501,32 @@ TEST_F(ViewManagerTest,
|
| // Contains().
|
| TEST_F(ViewManagerTest, SetActiveViewAcrossConnection) {
|
| ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree());
|
| - TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2);
|
| + WaitForTreeSizeToMatch(view_manager_2()->tree(), 2);
|
|
|
| View* view1_2 = View::Create(view_manager_2());
|
| EXPECT_DEATH(node1->SetActiveView(view1_2), "");
|
| }
|
|
|
| +// This test verifies that a node hierarchy constructed in one connection
|
| +// becomes entirely visible to the second connection when the hierarchy is
|
| +// attached.
|
| +TEST_F(ViewManagerTest, MapSubtreeOnAttach) {
|
| + ViewTreeNode* node1 = ViewTreeNode::Create(view_manager_1());
|
| + ViewTreeNode* node11 = CreateNodeInParent(node1);
|
| + View* view11 = View::Create(view_manager_1());
|
| + node11->SetActiveView(view11);
|
| + WaitForAllChangesToBeAcked(view_manager_1());
|
| +
|
| + // Now attach this node tree to the root & wait for it to show up in the
|
| + // second connection.
|
| + view_manager_1()->tree()->AddChild(node1);
|
| + WaitForTreeSizeToMatch(view_manager_2()->tree(), 3);
|
| +
|
| + ViewTreeNode* node11_2 = view_manager_2()->GetNodeById(node11->id());
|
| + View* view11_2 = view_manager_2()->GetViewById(view11->id());
|
| + EXPECT_TRUE(node11_2 != NULL);
|
| + EXPECT_EQ(view11_2, node11_2->active_view());
|
| +}
|
| +
|
| } // namespace view_manager
|
| } // namespace mojo
|
|
|