1 // Copyright 2015 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 "mandoline/tab/frame.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/test/test_timeouts.h"
13 #include "components/view_manager/public/cpp/lib/view_manager_client_impl.h"
14 #include "components/view_manager/public/cpp/view_manager_client_factory.h"
15 #include "components/view_manager/public/cpp/view_manager_delegate.h"
16 #include "components/view_manager/public/cpp/view_manager_init.h"
17 #include "components/view_manager/public/cpp/view_observer.h"
18 #include "mandoline/tab/frame.h"
19 #include "mandoline/tab/frame_tree.h"
20 #include "mandoline/tab/frame_tree_delegate.h"
21 #include "mandoline/tab/frame_user_data.h"
22 #include "mojo/application/public/cpp/application_connection.h"
23 #include "mojo/application/public/cpp/application_delegate.h"
24 #include "mojo/application/public/cpp/application_impl.h"
25 #include "mojo/application/public/cpp/application_test_base.h"
26 #include "mojo/application/public/cpp/service_provider_impl.h"
29 using mojo::ViewManager
;
35 base::RunLoop
* current_run_loop
= nullptr;
37 void TimeoutRunLoop(const base::Closure
& timeout_task
, bool* timeout
) {
38 CHECK(current_run_loop
);
43 bool DoRunLoopWithTimeout() {
44 if (current_run_loop
!= nullptr)
48 base::RunLoop run_loop
;
49 base::MessageLoop::current()->PostDelayedTask(
50 FROM_HERE
, base::Bind(&TimeoutRunLoop
, run_loop
.QuitClosure(), &timeout
),
51 TestTimeouts::action_timeout());
53 current_run_loop
= &run_loop
;
54 current_run_loop
->Run();
55 current_run_loop
= nullptr;
60 current_run_loop
->Quit();
61 current_run_loop
= nullptr;
66 class FrameTest
: public mojo::test::ApplicationTestBase
,
67 public mojo::ApplicationDelegate
,
68 public mojo::ViewManagerDelegate
{
70 FrameTest() : most_recent_view_manager_(nullptr), window_manager_(nullptr) {}
72 ViewManager
* most_recent_view_manager() { return most_recent_view_manager_
; }
74 // Overridden from ApplicationDelegate:
75 void Initialize(mojo::ApplicationImpl
* app
) override
{
76 view_manager_client_factory_
.reset(
77 new mojo::ViewManagerClientFactory(app
->shell(), this));
80 // ApplicationDelegate implementation.
81 bool ConfigureIncomingConnection(
82 mojo::ApplicationConnection
* connection
) override
{
83 connection
->AddService(view_manager_client_factory_
.get());
87 ViewManager
* window_manager() { return window_manager_
; }
89 // ApplicationTestBase:
90 ApplicationDelegate
* GetApplicationDelegate() override
{ return this; }
92 // Overridden from ViewManagerDelegate:
93 void OnEmbed(View
* root
) override
{
94 most_recent_view_manager_
= root
->view_manager();
97 void OnViewManagerDestroyed(ViewManager
* view_manager
) override
{}
100 // Overridden from testing::Test:
101 void SetUp() override
{
102 ApplicationTestBase::SetUp();
104 view_manager_init_
.reset(
105 new mojo::ViewManagerInit(application_impl(), this, nullptr));
106 ASSERT_TRUE(DoRunLoopWithTimeout());
107 std::swap(window_manager_
, most_recent_view_manager_
);
110 // Overridden from testing::Test:
111 void TearDown() override
{
112 view_manager_init_
.reset(); // Uses application_impl() from base class.
113 ApplicationTestBase::TearDown();
116 scoped_ptr
<mojo::ViewManagerInit
> view_manager_init_
;
118 scoped_ptr
<mojo::ViewManagerClientFactory
> view_manager_client_factory_
;
120 // Used to receive the most recent view manager loaded by an embed action.
121 ViewManager
* most_recent_view_manager_
;
122 // The View Manager connection held by the window manager (app running at the
124 ViewManager
* window_manager_
;
126 MOJO_DISALLOW_COPY_AND_ASSIGN(FrameTest
);
129 class TestFrameTreeDelegate
: public FrameTreeDelegate
{
131 TestFrameTreeDelegate() {}
132 ~TestFrameTreeDelegate() override
{}
134 // TestFrameTreeDelegate:
135 bool CanPostMessageEventToFrame(const Frame
* source
,
137 MessageEvent
* event
) override
{
140 void LoadingStateChanged(bool loading
) override
{}
141 void ProgressChanged(double progress
) override
{}
144 DISALLOW_COPY_AND_ASSIGN(TestFrameTreeDelegate
);
147 class TestFrameTreeClient
: public FrameTreeClient
{
149 TestFrameTreeClient() : connect_count_(0) {}
150 ~TestFrameTreeClient() override
{}
152 int connect_count() const { return connect_count_
; }
154 mojo::Array
<FrameDataPtr
> connect_frames() { return connect_frames_
.Pass(); }
156 mojo::Array
<FrameDataPtr
> adds() { return adds_
.Pass(); }
158 // TestFrameTreeClient:
159 void OnConnect(FrameTreeServerPtr server
,
160 mojo::Array
<FrameDataPtr
> frames
) override
{
162 connect_frames_
= frames
.Pass();
163 server_
= server
.Pass();
165 void OnFrameAdded(FrameDataPtr frame
) override
{
166 adds_
.push_back(frame
.Pass());
168 void OnFrameRemoved(uint32_t frame_id
) override
{}
169 void OnFrameNameChanged(uint32_t frame_id
,
170 const mojo::String
& name
) override
{}
174 mojo::Array
<FrameDataPtr
> connect_frames_
;
175 FrameTreeServerPtr server_
;
176 mojo::Array
<FrameDataPtr
> adds_
;
178 DISALLOW_COPY_AND_ASSIGN(TestFrameTreeClient
);
181 // Verifies the root gets a connect.
182 TEST_F(FrameTest
, RootGetsConnect
) {
183 TestFrameTreeDelegate tree_delegate
;
184 TestFrameTreeClient root_client
;
185 FrameTree
tree(window_manager()->GetRoot(), &tree_delegate
, &root_client
,
187 ASSERT_EQ(1, root_client
.connect_count());
188 mojo::Array
<FrameDataPtr
> frames
= root_client
.connect_frames();
189 ASSERT_EQ(1u, frames
.size());
190 EXPECT_EQ(tree
.root()->view()->id(), frames
[0]->frame_id
);
191 EXPECT_EQ(0u, frames
[0]->parent_id
);
194 // Verifies adding a child to the root.
195 TEST_F(FrameTest
, SingleChild
) {
196 TestFrameTreeDelegate tree_delegate
;
197 TestFrameTreeClient root_client
;
198 FrameTree
tree(window_manager()->GetRoot(), &tree_delegate
, &root_client
,
201 View
* child
= window_manager()->CreateView();
202 EXPECT_EQ(nullptr, Frame::FindFirstFrameAncestor(child
));
203 window_manager()->GetRoot()->AddChild(child
);
204 EXPECT_EQ(tree
.root(), Frame::FindFirstFrameAncestor(child
));
206 TestFrameTreeClient child_client
;
208 tree
.CreateAndAddFrame(child
, tree
.root(), &child_client
, nullptr);
209 EXPECT_EQ(tree
.root(), child_frame
->parent());
211 ASSERT_EQ(1, child_client
.connect_count());
212 mojo::Array
<FrameDataPtr
> frames_in_child
= child_client
.connect_frames();
213 // We expect 2 frames. One for the root, one for the child.
214 ASSERT_EQ(2u, frames_in_child
.size());
215 EXPECT_EQ(tree
.root()->view()->id(), frames_in_child
[0]->frame_id
);
216 EXPECT_EQ(0u, frames_in_child
[0]->parent_id
);
217 EXPECT_EQ(child_frame
->view()->id(), frames_in_child
[1]->frame_id
);
218 EXPECT_EQ(tree
.root()->view()->id(), frames_in_child
[1]->parent_id
);
220 // The root did the add, so it shouldn't get an add.
221 EXPECT_EQ(0u, root_client
.adds().size());
224 } // namespace mandoline