Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(234)

Side by Side Diff: services/ui/public/cpp/tests/window_tree_client_unittest.cc

Issue 2651593002: mus: Remove the old client lib. (Closed)
Patch Set: restore test Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "services/ui/public/cpp/window_tree_client.h"
6
7 #include <stdint.h>
8
9 #include "base/logging.h"
10 #include "base/macros.h"
11 #include "services/ui/common/util.h"
12 #include "services/ui/public/cpp/input_event_handler.h"
13 #include "services/ui/public/cpp/property_type_converters.h"
14 #include "services/ui/public/cpp/tests/test_window.h"
15 #include "services/ui/public/cpp/tests/test_window_tree.h"
16 #include "services/ui/public/cpp/tests/window_tree_client_private.h"
17 #include "services/ui/public/cpp/window.h"
18 #include "services/ui/public/cpp/window_observer.h"
19 #include "services/ui/public/cpp/window_private.h"
20 #include "services/ui/public/cpp/window_property.h"
21 #include "services/ui/public/cpp/window_tracker.h"
22 #include "services/ui/public/cpp/window_tree_client_delegate.h"
23 #include "services/ui/public/cpp/window_tree_client_observer.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "ui/display/test/test_screen.h"
26 #include "ui/events/event.h"
27 #include "ui/events/event_utils.h"
28 #include "ui/gfx/geometry/rect.h"
29
30 namespace ui {
31
32 namespace {
33
34 void DoNothingWithEventResult(mojom::EventResult result) {}
35
36 Id server_id(ui::Window* window) {
37 return WindowPrivate(window).server_id();
38 }
39
40 } // namespace
41
42 std::vector<uint8_t> Int32ToPropertyTransportValue(int32_t value) {
43 return mojo::ConvertTo<std::vector<uint8_t>>(value);
44 }
45
46 class TestWindowTreeClientDelegate : public WindowTreeClientDelegate {
47 public:
48 TestWindowTreeClientDelegate() {}
49 ~TestWindowTreeClientDelegate() override {}
50
51 ui::PointerEvent* last_event_observed() { return last_event_observed_.get(); }
52
53 void Reset() { last_event_observed_.reset(); }
54
55 // WindowTreeClientDelegate:
56 void OnEmbed(Window* root) override {}
57 void OnLostConnection(WindowTreeClient* client) override {}
58 void OnEmbedRootDestroyed(Window* root) override {}
59 void OnPointerEventObserved(const ui::PointerEvent& event,
60 Window* target) override {
61 last_event_observed_.reset(new ui::PointerEvent(event));
62 }
63
64 private:
65 std::unique_ptr<ui::PointerEvent> last_event_observed_;
66
67 DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClientDelegate);
68 };
69
70 class WindowTreeSetup {
71 public:
72 WindowTreeSetup() : tree_client_(&window_tree_delegate_, nullptr, nullptr) {
73 display::Screen::SetScreenInstance(&test_screen_);
74 WindowTreeClientPrivate(&tree_client_).OnEmbed(&window_tree_);
75 window_tree_.GetAndClearChangeId(nullptr);
76 }
77
78 ~WindowTreeSetup() { display::Screen::SetScreenInstance(nullptr); }
79
80 WindowTreeClient* client() {
81 return &tree_client_;
82 }
83
84 mojom::WindowTreeClient* window_tree_client() {
85 return static_cast<mojom::WindowTreeClient*>(&tree_client_);
86 }
87
88 TestWindowTree* window_tree() { return &window_tree_; }
89
90 TestWindowTreeClientDelegate* window_tree_delegate() {
91 return &window_tree_delegate_;
92 }
93
94 Window* GetFirstRoot() {
95 return client()->GetRoots().empty() ? nullptr
96 : *client()->GetRoots().begin();
97 }
98
99 private:
100 TestWindowTree window_tree_;
101 TestWindowTreeClientDelegate window_tree_delegate_;
102 WindowTreeClient tree_client_;
103
104 // Dummy screen required to be the screen instance.
105 display::test::TestScreen test_screen_;
106
107 DISALLOW_COPY_AND_ASSIGN(WindowTreeSetup);
108 };
109
110 class TestInputEventHandler : public InputEventHandler {
111 public:
112 TestInputEventHandler()
113 : received_event_(false), should_manually_ack_(false) {}
114 ~TestInputEventHandler() override {}
115
116 void set_should_manually_ack() { should_manually_ack_ = true; }
117
118 void AckEvent() {
119 DCHECK(should_manually_ack_);
120 DCHECK(!ack_callback_.is_null());
121 ack_callback_.Run(mojom::EventResult::HANDLED);
122 ack_callback_ = base::Bind(&DoNothingWithEventResult);
123 }
124
125 void Reset() {
126 received_event_ = false;
127 ack_callback_ = base::Bind(&DoNothingWithEventResult);
128 }
129 bool received_event() const { return received_event_; }
130
131 private:
132 // InputEventHandler:
133 void OnWindowInputEvent(
134 Window* target,
135 const ui::Event& event,
136 std::unique_ptr<base::Callback<void(mojom::EventResult)>>* ack_callback)
137 override {
138 EXPECT_FALSE(received_event_)
139 << "Observer was not reset after receiving event.";
140 received_event_ = true;
141 if (should_manually_ack_) {
142 ack_callback_ = *ack_callback->get();
143 ack_callback->reset();
144 }
145 }
146
147 bool received_event_;
148 bool should_manually_ack_;
149 base::Callback<void(mojom::EventResult)> ack_callback_;
150
151 DISALLOW_COPY_AND_ASSIGN(TestInputEventHandler);
152 };
153
154 using WindowTreeClientTest = testing::Test;
155
156 // Verifies bounds are reverted if the server replied that the change failed.
157 TEST_F(WindowTreeClientTest, SetBoundsFailed) {
158 WindowTreeSetup setup;
159 Window* root = setup.GetFirstRoot();
160 ASSERT_TRUE(root);
161 const gfx::Rect original_bounds(root->bounds());
162 const gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100));
163 ASSERT_NE(new_bounds, root->bounds());
164 root->SetBounds(new_bounds);
165 uint32_t change_id;
166 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
167 setup.window_tree_client()->OnChangeCompleted(change_id, false);
168 EXPECT_EQ(original_bounds, root->bounds());
169 }
170
171 // Simulates a bounds change, and while the bounds change is in flight the
172 // server replies with a new bounds and the original bounds change fails.
173 TEST_F(WindowTreeClientTest, SetBoundsFailedWithPendingChange) {
174 WindowTreeSetup setup;
175 Window* root = setup.GetFirstRoot();
176 ASSERT_TRUE(root);
177 const gfx::Rect original_bounds(root->bounds());
178 const gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100));
179 ASSERT_NE(new_bounds, root->bounds());
180 root->SetBounds(new_bounds);
181 EXPECT_EQ(new_bounds, root->bounds());
182 uint32_t change_id;
183 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
184
185 // Simulate the server responding with a bounds change.
186 const gfx::Rect server_changed_bounds(gfx::Rect(0, 0, 101, 102));
187 setup.window_tree_client()->OnWindowBoundsChanged(
188 server_id(root), original_bounds, server_changed_bounds);
189
190 // This shouldn't trigger the bounds changing yet.
191 EXPECT_EQ(new_bounds, root->bounds());
192
193 // Tell the client the change failed, which should trigger failing to the
194 // most recent bounds from server.
195 setup.window_tree_client()->OnChangeCompleted(change_id, false);
196 EXPECT_EQ(server_changed_bounds, root->bounds());
197
198 // Simulate server changing back to original bounds. Should take immediately.
199 setup.window_tree_client()->OnWindowBoundsChanged(
200 server_id(root), server_changed_bounds, original_bounds);
201 EXPECT_EQ(original_bounds, root->bounds());
202 }
203
204 TEST_F(WindowTreeClientTest, TwoInFlightBoundsChangesBothCanceled) {
205 WindowTreeSetup setup;
206 Window* root = setup.GetFirstRoot();
207 ASSERT_TRUE(root);
208 const gfx::Rect original_bounds(root->bounds());
209 const gfx::Rect bounds1(gfx::Rect(0, 0, 100, 100));
210 const gfx::Rect bounds2(gfx::Rect(0, 0, 100, 102));
211 root->SetBounds(bounds1);
212 EXPECT_EQ(bounds1, root->bounds());
213 uint32_t change_id1;
214 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
215
216 root->SetBounds(bounds2);
217 EXPECT_EQ(bounds2, root->bounds());
218 uint32_t change_id2;
219 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id2));
220
221 // Tell the client change 1 failed. As there is a still a change in flight
222 // nothing should happen.
223 setup.window_tree_client()->OnChangeCompleted(change_id1, false);
224 EXPECT_EQ(bounds2, root->bounds());
225
226 // And tell the client change 2 failed too. Should now fallback to original
227 // bounds.
228 setup.window_tree_client()->OnChangeCompleted(change_id2, false);
229 EXPECT_EQ(original_bounds, root->bounds());
230 }
231
232 // Verifies properties are reverted if the server replied that the change
233 // failed.
234 TEST_F(WindowTreeClientTest, SetPropertyFailed) {
235 WindowTreeSetup setup;
236 Window* root = setup.GetFirstRoot();
237 ASSERT_TRUE(root);
238 ASSERT_FALSE(root->HasSharedProperty("foo"));
239 const int32_t new_value = 11;
240 root->SetSharedProperty("foo", new_value);
241 ASSERT_TRUE(root->HasSharedProperty("foo"));
242 EXPECT_EQ(new_value, root->GetSharedProperty<int32_t>("foo"));
243 uint32_t change_id;
244 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
245 setup.window_tree_client()->OnChangeCompleted(change_id, false);
246 EXPECT_FALSE(root->HasSharedProperty("foo"));
247 }
248
249 // Simulates a property change, and while the property change is in flight the
250 // server replies with a new property and the original property change fails.
251 TEST_F(WindowTreeClientTest, SetPropertyFailedWithPendingChange) {
252 WindowTreeSetup setup;
253 Window* root = setup.GetFirstRoot();
254 ASSERT_TRUE(root);
255 const int32_t value1 = 11;
256 root->SetSharedProperty("foo", value1);
257 ASSERT_TRUE(root->HasSharedProperty("foo"));
258 EXPECT_EQ(value1, root->GetSharedProperty<int32_t>("foo"));
259 uint32_t change_id;
260 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
261
262 // Simulate the server responding with a different value.
263 const int32_t server_value = 12;
264 setup.window_tree_client()->OnWindowSharedPropertyChanged(
265 server_id(root), "foo", Int32ToPropertyTransportValue(server_value));
266
267 // This shouldn't trigger the property changing yet.
268 ASSERT_TRUE(root->HasSharedProperty("foo"));
269 EXPECT_EQ(value1, root->GetSharedProperty<int32_t>("foo"));
270
271 // Tell the client the change failed, which should trigger failing to the
272 // most recent value from server.
273 setup.window_tree_client()->OnChangeCompleted(change_id, false);
274 ASSERT_TRUE(root->HasSharedProperty("foo"));
275 EXPECT_EQ(server_value, root->GetSharedProperty<int32_t>("foo"));
276
277 // Simulate server changing back to value1. Should take immediately.
278 setup.window_tree_client()->OnWindowSharedPropertyChanged(
279 server_id(root), "foo", Int32ToPropertyTransportValue(value1));
280 ASSERT_TRUE(root->HasSharedProperty("foo"));
281 EXPECT_EQ(value1, root->GetSharedProperty<int32_t>("foo"));
282 }
283
284 // Verifies visible is reverted if the server replied that the change failed.
285 TEST_F(WindowTreeClientTest, SetVisibleFailed) {
286 WindowTreeSetup setup;
287 Window* root = setup.GetFirstRoot();
288 ASSERT_TRUE(root);
289 const bool original_visible = root->visible();
290 const bool new_visible = !original_visible;
291 ASSERT_NE(new_visible, root->visible());
292 root->SetVisible(new_visible);
293 uint32_t change_id;
294 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
295 setup.window_tree_client()->OnChangeCompleted(change_id, false);
296 EXPECT_EQ(original_visible, root->visible());
297 }
298
299 // Simulates a visible change, and while the visible change is in flight the
300 // server replies with a new visible and the original visible change fails.
301 TEST_F(WindowTreeClientTest, SetVisibleFailedWithPendingChange) {
302 WindowTreeSetup setup;
303 Window* root = setup.GetFirstRoot();
304 ASSERT_TRUE(root);
305 const bool original_visible = root->visible();
306 const bool new_visible = !original_visible;
307 ASSERT_NE(new_visible, root->visible());
308 root->SetVisible(new_visible);
309 EXPECT_EQ(new_visible, root->visible());
310 uint32_t change_id;
311 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
312
313 // Simulate the server responding with a visible change.
314 const bool server_changed_visible = !new_visible;
315 setup.window_tree_client()->OnWindowVisibilityChanged(server_id(root),
316 server_changed_visible);
317
318 // This shouldn't trigger visible changing yet.
319 EXPECT_EQ(new_visible, root->visible());
320
321 // Tell the client the change failed, which should trigger failing to the
322 // most recent visible from server.
323 setup.window_tree_client()->OnChangeCompleted(change_id, false);
324 EXPECT_EQ(server_changed_visible, root->visible());
325
326 // Simulate server changing back to original visible. Should take immediately.
327 setup.window_tree_client()->OnWindowVisibilityChanged(server_id(root),
328 original_visible);
329 EXPECT_EQ(original_visible, root->visible());
330 }
331
332 // Verifies that local opacity is not changed if the server replied that the
333 // change succeeded.
334 TEST_F(WindowTreeClientTest, SetOpacitySucceeds) {
335 WindowTreeSetup setup;
336 Window* root = setup.GetFirstRoot();
337 ASSERT_TRUE(root);
338 const float original_opacity = root->opacity();
339 const float new_opacity = 0.5f;
340 ASSERT_NE(new_opacity, original_opacity);
341 ASSERT_NE(new_opacity, root->opacity());
342 root->SetOpacity(new_opacity);
343 uint32_t change_id;
344 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
345 setup.window_tree_client()->OnChangeCompleted(change_id, true);
346 EXPECT_EQ(new_opacity, root->opacity());
347 }
348
349 // Verifies that opacity is reverted if the server replied that the change
350 // failed.
351 TEST_F(WindowTreeClientTest, SetOpacityFailed) {
352 WindowTreeSetup setup;
353 Window* root = setup.GetFirstRoot();
354 ASSERT_TRUE(root);
355 const float original_opacity = root->opacity();
356 const float new_opacity = 0.5f;
357 ASSERT_NE(new_opacity, root->opacity());
358 root->SetOpacity(new_opacity);
359 uint32_t change_id;
360 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
361 setup.window_tree_client()->OnChangeCompleted(change_id, false);
362 EXPECT_EQ(original_opacity, root->opacity());
363 }
364
365 // Simulates the server changing the opacitry while there is an opacity change
366 // in flight, causing the requested change to fail.
367 TEST_F(WindowTreeClientTest, SetOpacityFailedWithPendingChange) {
368 WindowTreeSetup setup;
369 Window* root = setup.GetFirstRoot();
370 ASSERT_TRUE(root);
371 const float original_opacity = root->opacity();
372 const float new_opacity = 0.5f;
373 ASSERT_NE(new_opacity, root->opacity());
374 root->SetOpacity(new_opacity);
375 EXPECT_EQ(new_opacity, root->opacity());
376 uint32_t change_id;
377 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
378
379 // Simulate the server responding with an opacity change.
380 const float server_changed_opacity = 0.75f;
381 setup.window_tree_client()->OnWindowOpacityChanged(
382 server_id(root), original_opacity, server_changed_opacity);
383
384 // This shouldn't trigger opacity changing yet.
385 EXPECT_EQ(new_opacity, root->opacity());
386
387 // Tell the client the change failed, which should trigger failing to the
388 // most recent opacity from server.
389 setup.window_tree_client()->OnChangeCompleted(change_id, false);
390 EXPECT_EQ(server_changed_opacity, root->opacity());
391
392 // Simulate server changing back to original opacity. Should take immediately.
393 setup.window_tree_client()->OnWindowOpacityChanged(
394 server_id(root), server_changed_opacity, original_opacity);
395 EXPECT_EQ(original_opacity, root->opacity());
396 }
397
398 // Tests that when there are multiple changes in flight, that failing changes
399 // update the revert state of subsequent changes.
400 TEST_F(WindowTreeClientTest, SetOpacityFailedWithMultiplePendingChange) {
401 WindowTreeSetup setup;
402 Window* root = setup.GetFirstRoot();
403 ASSERT_TRUE(root);
404 const float original_opacity = root->opacity();
405 const float new_opacity = 0.5f;
406 ASSERT_NE(new_opacity, root->opacity());
407 root->SetOpacity(new_opacity);
408 uint32_t change_id1;
409 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
410
411 const float second_new_opacity = 0.75f;
412 ASSERT_NE(second_new_opacity, root->opacity());
413 root->SetOpacity(second_new_opacity);
414 uint32_t change_id2;
415 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id2));
416
417 // Canceling the first one, while there is another in flight, should not
418 // change the local opacity.
419 setup.window_tree_client()->OnChangeCompleted(change_id1, false);
420 EXPECT_EQ(second_new_opacity, root->opacity());
421
422 // The previous cancelation should have updated the revert value of the in
423 // flight change.
424 setup.window_tree_client()->OnChangeCompleted(change_id2, false);
425 EXPECT_EQ(original_opacity, root->opacity());
426 }
427
428 // Verifies |is_modal| is reverted if the server replied that the change failed.
429 TEST_F(WindowTreeClientTest, SetModalFailed) {
430 WindowTreeSetup setup;
431 Window* root = setup.GetFirstRoot();
432 ASSERT_TRUE(root);
433 EXPECT_FALSE(root->is_modal());
434 root->SetModal();
435 uint32_t change_id;
436 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
437 EXPECT_TRUE(root->is_modal());
438 setup.window_tree_client()->OnChangeCompleted(change_id, false);
439 EXPECT_FALSE(root->is_modal());
440 }
441
442 TEST_F(WindowTreeClientTest, InputEventBasic) {
443 WindowTreeSetup setup;
444 Window* root = setup.GetFirstRoot();
445 ASSERT_TRUE(root);
446
447 TestInputEventHandler event_handler;
448 root->set_input_event_handler(&event_handler);
449
450 std::unique_ptr<ui::Event> ui_event(
451 new ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
452 ui::EventTimeForNow(), ui::EF_NONE, 0));
453 setup.window_tree_client()->OnWindowInputEvent(
454 1, server_id(root), ui::Event::Clone(*ui_event.get()), 0);
455 EXPECT_TRUE(event_handler.received_event());
456 EXPECT_TRUE(setup.window_tree()->WasEventAcked(1));
457 event_handler.Reset();
458
459 event_handler.set_should_manually_ack();
460 setup.window_tree_client()->OnWindowInputEvent(
461 33, server_id(root), ui::Event::Clone(*ui_event.get()), 0);
462 EXPECT_TRUE(event_handler.received_event());
463 EXPECT_FALSE(setup.window_tree()->WasEventAcked(33));
464
465 event_handler.AckEvent();
466 EXPECT_TRUE(setup.window_tree()->WasEventAcked(33));
467 }
468
469 // Tests pointer watchers triggered by events that did not hit a target in this
470 // window tree.
471 TEST_F(WindowTreeClientTest, OnPointerEventObserved) {
472 WindowTreeSetup setup;
473 Window* root = setup.GetFirstRoot();
474 ASSERT_TRUE(root);
475
476 // Start a pointer watcher for all events excluding move events.
477 setup.client()->StartPointerWatcher(false /* want_moves */);
478
479 // Simulate the server sending an observed event.
480 std::unique_ptr<ui::PointerEvent> pointer_event_down(new ui::PointerEvent(
481 ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 1,
482 0, ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH),
483 base::TimeTicks()));
484 setup.window_tree_client()->OnPointerEventObserved(
485 std::move(pointer_event_down), 0u);
486
487 // Delegate sensed the event.
488 ui::Event* last_event = setup.window_tree_delegate()->last_event_observed();
489 EXPECT_EQ(ui::ET_POINTER_DOWN, last_event->type());
490 EXPECT_EQ(ui::EF_CONTROL_DOWN, last_event->flags());
491 setup.window_tree_delegate()->Reset();
492
493 // Stop the pointer watcher.
494 setup.client()->StopPointerWatcher();
495
496 // Simulate another event from the server.
497 std::unique_ptr<ui::PointerEvent> pointer_event_up(new ui::PointerEvent(
498 ui::ET_POINTER_UP, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 1, 0,
499 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH),
500 base::TimeTicks()));
501 setup.window_tree_client()->OnPointerEventObserved(
502 std::move(pointer_event_up), 0u);
503
504 // No event was sensed.
505 EXPECT_FALSE(setup.window_tree_delegate()->last_event_observed());
506 }
507
508 // Tests pointer watchers triggered by events that hit this window tree.
509 TEST_F(WindowTreeClientTest, OnWindowInputEventWithPointerWatcher) {
510 WindowTreeSetup setup;
511 Window* root = setup.GetFirstRoot();
512 ASSERT_TRUE(root);
513
514 // Start a pointer watcher for all events excluding move events.
515 setup.client()->StartPointerWatcher(false /* want_moves */);
516
517 // Simulate the server dispatching an event that also matched the observer.
518 std::unique_ptr<ui::PointerEvent> pointer_event_down(new ui::PointerEvent(
519 ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 1,
520 0, ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH),
521 base::TimeTicks()));
522 setup.window_tree_client()->OnWindowInputEvent(
523 1, server_id(root), std::move(pointer_event_down), true);
524
525 // Delegate sensed the event.
526 ui::Event* last_event = setup.window_tree_delegate()->last_event_observed();
527 EXPECT_EQ(ui::ET_POINTER_DOWN, last_event->type());
528 EXPECT_EQ(ui::EF_CONTROL_DOWN, last_event->flags());
529 }
530
531 // Verifies focus is reverted if the server replied that the change failed.
532 TEST_F(WindowTreeClientTest, SetFocusFailed) {
533 WindowTreeSetup setup;
534 Window* root = setup.GetFirstRoot();
535 ASSERT_TRUE(root);
536 root->SetVisible(true);
537 Window* child = setup.client()->NewWindow();
538 child->SetVisible(true);
539 root->AddChild(child);
540 Window* original_focus = setup.client()->GetFocusedWindow();
541 Window* new_focus = child;
542 ASSERT_NE(new_focus, original_focus);
543 new_focus->SetFocus();
544 ASSERT_TRUE(new_focus->HasFocus());
545 uint32_t change_id;
546 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
547 setup.window_tree_client()->OnChangeCompleted(change_id, false);
548 EXPECT_EQ(original_focus, setup.client()->GetFocusedWindow());
549 }
550
551 // Simulates a focus change, and while the focus change is in flight the server
552 // replies with a new focus and the original focus change fails.
553 TEST_F(WindowTreeClientTest, SetFocusFailedWithPendingChange) {
554 WindowTreeSetup setup;
555 Window* root = setup.GetFirstRoot();
556 ASSERT_TRUE(root);
557 root->SetVisible(true);
558 Window* child1 = setup.client()->NewWindow();
559 child1->SetVisible(true);
560 root->AddChild(child1);
561 Window* child2 = setup.client()->NewWindow();
562 child2->SetVisible(true);
563 root->AddChild(child2);
564 Window* original_focus = setup.client()->GetFocusedWindow();
565 Window* new_focus = child1;
566 ASSERT_NE(new_focus, original_focus);
567 new_focus->SetFocus();
568 ASSERT_TRUE(new_focus->HasFocus());
569 uint32_t change_id;
570 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
571
572 // Simulate the server responding with a focus change.
573 setup.window_tree_client()->OnWindowFocused(server_id(child2));
574
575 // This shouldn't trigger focus changing yet.
576 EXPECT_TRUE(child1->HasFocus());
577
578 // Tell the client the change failed, which should trigger failing to the
579 // most recent focus from server.
580 setup.window_tree_client()->OnChangeCompleted(change_id, false);
581 EXPECT_FALSE(child1->HasFocus());
582 EXPECT_TRUE(child2->HasFocus());
583 EXPECT_EQ(child2, setup.client()->GetFocusedWindow());
584
585 // Simulate server changing focus to child1. Should take immediately.
586 setup.window_tree_client()->OnWindowFocused(server_id(child1));
587 EXPECT_TRUE(child1->HasFocus());
588 }
589
590 TEST_F(WindowTreeClientTest, FocusOnRemovedWindowWithInFlightFocusChange) {
591 WindowTreeSetup setup;
592 Window* root = setup.GetFirstRoot();
593 ASSERT_TRUE(root);
594 root->SetVisible(true);
595 Window* child1 = setup.client()->NewWindow();
596 child1->SetVisible(true);
597 root->AddChild(child1);
598 Window* child2 = setup.client()->NewWindow();
599 child2->SetVisible(true);
600 root->AddChild(child2);
601
602 child1->SetFocus();
603 uint32_t change_id;
604 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
605
606 // Destroy child1, which should set focus to null.
607 child1->Destroy();
608 EXPECT_EQ(nullptr, setup.client()->GetFocusedWindow());
609
610 // Server changes focus to 2.
611 setup.window_tree_client()->OnWindowFocused(server_id(child2));
612 // Shouldn't take immediately.
613 EXPECT_FALSE(child2->HasFocus());
614
615 // Ack the change, focus should still be null.
616 setup.window_tree_client()->OnChangeCompleted(change_id, true);
617 EXPECT_EQ(nullptr, setup.client()->GetFocusedWindow());
618
619 // Change to 2 again, this time it should take.
620 setup.window_tree_client()->OnWindowFocused(server_id(child2));
621 EXPECT_TRUE(child2->HasFocus());
622 }
623
624 class ToggleVisibilityFromDestroyedObserver : public WindowObserver {
625 public:
626 explicit ToggleVisibilityFromDestroyedObserver(Window* window)
627 : window_(window) {
628 window_->AddObserver(this);
629 }
630
631 ToggleVisibilityFromDestroyedObserver() { EXPECT_FALSE(window_); }
632
633 // WindowObserver:
634 void OnWindowDestroyed(Window* window) override {
635 window_->SetVisible(!window->visible());
636 window_->RemoveObserver(this);
637 window_ = nullptr;
638 }
639
640 private:
641 Window* window_;
642
643 DISALLOW_COPY_AND_ASSIGN(ToggleVisibilityFromDestroyedObserver);
644 };
645
646 TEST_F(WindowTreeClientTest, ToggleVisibilityFromWindowDestroyed) {
647 WindowTreeSetup setup;
648 Window* root = setup.GetFirstRoot();
649 ASSERT_TRUE(root);
650 Window* child1 = setup.client()->NewWindow();
651 root->AddChild(child1);
652 ToggleVisibilityFromDestroyedObserver toggler(child1);
653 // Destroying the window triggers
654 // ToggleVisibilityFromDestroyedObserver::OnWindowDestroyed(), which toggles
655 // the visibility of the window. Ack the change, which should not crash or
656 // trigger DCHECKs.
657 child1->Destroy();
658 uint32_t change_id;
659 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
660 setup.window_tree_client()->OnChangeCompleted(change_id, true);
661 }
662
663 TEST_F(WindowTreeClientTest, NewTopLevelWindow) {
664 WindowTreeSetup setup;
665 Window* root1 = setup.GetFirstRoot();
666 ASSERT_TRUE(root1);
667 Window* root2 = setup.client()->NewTopLevelWindow(nullptr);
668 ASSERT_TRUE(root2);
669 EXPECT_TRUE(WindowPrivate(root2).parent_drawn());
670 ASSERT_NE(root2, root1);
671 EXPECT_NE(server_id(root2), server_id(root1));
672 EXPECT_EQ(2u, setup.client()->GetRoots().size());
673 EXPECT_TRUE(setup.client()->GetRoots().count(root1) > 0u);
674 EXPECT_TRUE(setup.client()->GetRoots().count(root2) > 0u);
675
676 // Ack the request to the windowtree to create the new window.
677 uint32_t change_id;
678 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
679 EXPECT_EQ(setup.window_tree()->window_id(), server_id(root2));
680
681 mojom::WindowDataPtr data = mojom::WindowData::New();
682 data->window_id = server_id(root2);
683 const int64_t display_id = 1;
684 setup.window_tree_client()->OnTopLevelCreated(change_id, std::move(data),
685 display_id, false);
686
687 EXPECT_FALSE(WindowPrivate(root2).parent_drawn());
688
689 // Should not be able to add a top level as a child of another window.
690 root1->AddChild(root2);
691 ASSERT_EQ(nullptr, root2->parent());
692
693 // Destroy the first root, shouldn't initiate tear down.
694 root1->Destroy();
695 root1 = nullptr;
696 EXPECT_EQ(1u, setup.client()->GetRoots().size());
697 EXPECT_TRUE(setup.client()->GetRoots().count(root2) > 0u);
698 }
699
700 TEST_F(WindowTreeClientTest, NewTopLevelWindowGetsPropertiesFromData) {
701 WindowTreeSetup setup;
702 Window* root1 = setup.GetFirstRoot();
703 ASSERT_TRUE(root1);
704 Window* root2 = setup.client()->NewTopLevelWindow(nullptr);
705 ASSERT_TRUE(root2);
706
707 EXPECT_FALSE(root2->IsDrawn());
708 EXPECT_FALSE(root2->visible());
709
710 // Ack the request to the windowtree to create the new window.
711 uint32_t change_id;
712 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
713 EXPECT_EQ(setup.window_tree()->window_id(), server_id(root2));
714
715 mojom::WindowDataPtr data = mojom::WindowData::New();
716 data->window_id = server_id(root2);
717 data->bounds.SetRect(1, 2, 3, 4);
718 data->visible = true;
719 const int64_t display_id = 1;
720 setup.window_tree_client()->OnTopLevelCreated(change_id, std::move(data),
721 display_id, true);
722
723 // Make sure all the properties took.
724 EXPECT_TRUE(root2->IsDrawn());
725 EXPECT_TRUE(root2->visible());
726 EXPECT_EQ(1, root2->display_id());
727 EXPECT_EQ(gfx::Rect(1, 2, 3, 4), root2->bounds());
728 }
729
730 TEST_F(WindowTreeClientTest, NewTopLevelWindowGetsAllChangesInFlight) {
731 WindowTreeSetup setup;
732 Window* root1 = setup.GetFirstRoot();
733 ASSERT_TRUE(root1);
734 Window* root2 = setup.client()->NewTopLevelWindow(nullptr);
735 ASSERT_TRUE(root2);
736
737 EXPECT_FALSE(root2->IsDrawn());
738 EXPECT_FALSE(root2->visible());
739
740 // Get the id of the in flight change for creating the new window.
741 uint32_t new_window_in_flight_change_id;
742 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(
743 &new_window_in_flight_change_id));
744 EXPECT_EQ(setup.window_tree()->window_id(), server_id(root2));
745
746 // Make visibility go from false->true->false. Don't ack immediately.
747 root2->SetVisible(true);
748 uint32_t vis_in_flight_change_id1;
749 ASSERT_TRUE(
750 setup.window_tree()->GetAndClearChangeId(&vis_in_flight_change_id1));
751 EXPECT_NE(new_window_in_flight_change_id, vis_in_flight_change_id1);
752 root2->SetVisible(false);
753 uint32_t vis_in_flight_change_id2;
754 ASSERT_TRUE(
755 setup.window_tree()->GetAndClearChangeId(&vis_in_flight_change_id2));
756 EXPECT_NE(vis_in_flight_change_id1, vis_in_flight_change_id2);
757
758 // Change bounds to 5, 6, 7, 8.
759 root2->SetBounds(gfx::Rect(5, 6, 7, 8));
760 uint32_t bounds_in_flight_change_id;
761 ASSERT_TRUE(
762 setup.window_tree()->GetAndClearChangeId(&bounds_in_flight_change_id));
763 EXPECT_NE(vis_in_flight_change_id2, bounds_in_flight_change_id);
764
765 root2->SetSharedProperty<std::string>("xx", "client_xx");
766 uint32_t property_in_flight_change_id;
767 ASSERT_TRUE(
768 setup.window_tree()->GetAndClearChangeId(&property_in_flight_change_id));
769 EXPECT_NE(bounds_in_flight_change_id, property_in_flight_change_id);
770
771 // Ack the new window top level window. Vis and bounds shouldn't change.
772 mojom::WindowDataPtr data = mojom::WindowData::New();
773 data->window_id = server_id(root2);
774 data->bounds.SetRect(1, 2, 3, 4);
775 data->visible = true;
776 constexpr char kXxName[] = "server_xx";
777 data->properties["xx"] =
778 std::vector<uint8_t>(kXxName, kXxName + strlen(kXxName));
779 constexpr char kYyName[] = "server_yy";
780 data->properties["yy"] =
781 std::vector<uint8_t>(kYyName, kYyName + strlen(kYyName));
782 const int64_t display_id = 1;
783 setup.window_tree_client()->OnTopLevelCreated(
784 new_window_in_flight_change_id, std::move(data), display_id, true);
785
786 // The only value that should take effect is the property for 'yy' as it was
787 // not in flight.
788 EXPECT_TRUE(WindowPrivate(root2).parent_drawn());
789 EXPECT_FALSE(root2->visible());
790 EXPECT_EQ(1, root2->display_id());
791 EXPECT_EQ(gfx::Rect(5, 6, 7, 8), root2->bounds());
792 EXPECT_EQ(2u, root2->shared_properties().size());
793 ASSERT_TRUE(root2->HasSharedProperty("yy"));
794 EXPECT_EQ("server_yy", root2->GetSharedProperty<std::string>("yy"));
795 ASSERT_TRUE(root2->HasSharedProperty("xx"));
796 EXPECT_EQ("client_xx", root2->GetSharedProperty<std::string>("xx"));
797
798 // Tell the client the changes failed. This should cause the values to change
799 // to that of the server.
800 setup.window_tree_client()->OnChangeCompleted(vis_in_flight_change_id1,
801 false);
802 EXPECT_FALSE(root2->visible());
803 setup.window_tree_client()->OnChangeCompleted(vis_in_flight_change_id2,
804 false);
805 EXPECT_TRUE(root2->visible());
806 setup.window_tree_client()->OnChangeCompleted(bounds_in_flight_change_id,
807 false);
808 EXPECT_EQ(gfx::Rect(1, 2, 3, 4), root2->bounds());
809 setup.window_tree_client()->OnChangeCompleted(property_in_flight_change_id,
810 false);
811 EXPECT_EQ(2u, root2->shared_properties().size());
812 ASSERT_TRUE(root2->HasSharedProperty("yy"));
813 EXPECT_EQ("server_yy", root2->GetSharedProperty<std::string>("yy"));
814 ASSERT_TRUE(root2->HasSharedProperty("xx"));
815 EXPECT_EQ("server_xx", root2->GetSharedProperty<std::string>("xx"));
816 }
817
818 // Tests that if the client has multiple unowned windows, and one of them is a
819 // transient child to another, the teardown can happen cleanly.
820 TEST_F(WindowTreeClientTest, MultipleUnOwnedWindowsDuringDestruction) {
821 std::unique_ptr<WindowTreeSetup> setup(new WindowTreeSetup());
822 Window* root1 = setup->GetFirstRoot();
823 ASSERT_TRUE(root1);
824 Window* root2 = setup->client()->NewTopLevelWindow(nullptr);
825 ASSERT_TRUE(root2);
826 root1->AddTransientWindow(root2);
827
828 WindowTracker tracker;
829 tracker.Add(root1);
830 tracker.Add(root2);
831 setup.reset();
832 EXPECT_TRUE(tracker.windows().empty());
833 }
834
835 TEST_F(WindowTreeClientTest, TopLevelWindowDestroyedBeforeCreateComplete) {
836 WindowTreeSetup setup;
837 Window* root1 = setup.GetFirstRoot();
838 ASSERT_TRUE(root1);
839 Window* root2 = setup.client()->NewTopLevelWindow(nullptr);
840 ASSERT_TRUE(root2);
841 ASSERT_EQ(2u, setup.client()->GetRoots().size());
842
843 // Get the id of the in flight change for creating the new window.
844 uint32_t change_id;
845 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
846 EXPECT_EQ(setup.window_tree()->window_id(), server_id(root2));
847
848 mojom::WindowDataPtr data = mojom::WindowData::New();
849 data->window_id = server_id(root2);
850
851 // Destroy the window before the server has a chance to ack the window
852 // creation.
853 root2->Destroy();
854 EXPECT_EQ(1u, setup.client()->GetRoots().size());
855
856 const int64_t display_id = 1;
857 setup.window_tree_client()->OnTopLevelCreated(change_id, std::move(data),
858 display_id, true);
859 EXPECT_EQ(1u, setup.client()->GetRoots().size());
860 }
861
862 // Tests both SetCapture and ReleaseCapture, to ensure that Window is properly
863 // updated on failures.
864 TEST_F(WindowTreeClientTest, ExplicitCapture) {
865 WindowTreeSetup setup;
866 Window* root = setup.GetFirstRoot();
867 ASSERT_TRUE(root);
868
869 root->SetCapture();
870 EXPECT_TRUE(root->HasCapture());
871 uint32_t change_id1;
872 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
873 setup.window_tree_client()->OnChangeCompleted(change_id1, false);
874 EXPECT_FALSE(root->HasCapture());
875
876 root->SetCapture();
877 EXPECT_TRUE(root->HasCapture());
878 uint32_t change_id2;
879 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id2));
880 setup.window_tree_client()->OnChangeCompleted(change_id2, true);
881 EXPECT_TRUE(root->HasCapture());
882
883 root->ReleaseCapture();
884 EXPECT_FALSE(root->HasCapture());
885 uint32_t change_id3;
886 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id3));
887 setup.window_tree_client()->OnChangeCompleted(change_id3, false);
888 EXPECT_TRUE(root->HasCapture());
889
890 root->ReleaseCapture();
891 uint32_t change_id4;
892 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id4));
893 setup.window_tree_client()->OnChangeCompleted(change_id4, true);
894 EXPECT_FALSE(root->HasCapture());
895 }
896
897 // Tests that when capture is lost, that the window tree updates properly.
898 TEST_F(WindowTreeClientTest, LostCapture) {
899 WindowTreeSetup setup;
900 Window* root = setup.GetFirstRoot();
901 ASSERT_TRUE(root);
902
903 root->SetCapture();
904 EXPECT_TRUE(root->HasCapture());
905 uint32_t change_id1;
906 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
907 setup.window_tree_client()->OnChangeCompleted(change_id1, true);
908 EXPECT_TRUE(root->HasCapture());
909
910 // The second SetCapture should be ignored.
911 root->SetCapture();
912 uint32_t change_id2;
913 ASSERT_FALSE(setup.window_tree()->GetAndClearChangeId(&change_id2));
914
915 setup.window_tree_client()->OnCaptureChanged(0, server_id(root));
916 EXPECT_FALSE(root->HasCapture());
917 }
918
919 // Tests that when capture is lost, while there is a release capture request
920 // inflight, that the revert value of that request is updated correctly.
921 TEST_F(WindowTreeClientTest, LostCaptureDifferentInFlightChange) {
922 WindowTreeSetup setup;
923 Window* root = setup.GetFirstRoot();
924 ASSERT_TRUE(root);
925
926 root->SetCapture();
927 EXPECT_TRUE(root->HasCapture());
928 uint32_t change_id1;
929 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
930 setup.window_tree_client()->OnChangeCompleted(change_id1, true);
931 EXPECT_TRUE(root->HasCapture());
932
933 // The ReleaseCapture should be updated to the revert of the SetCapture.
934 root->ReleaseCapture();
935 uint32_t change_id2;
936 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id2));
937
938 setup.window_tree_client()->OnCaptureChanged(0, server_id(root));
939 EXPECT_FALSE(root->HasCapture());
940
941 setup.window_tree_client()->OnChangeCompleted(change_id2, false);
942 EXPECT_FALSE(root->HasCapture());
943 }
944
945 // Tests that while two windows can inflight capture requests, that the
946 // WindowTreeClient only identifies one as having the current capture.
947 TEST_F(WindowTreeClientTest, TwoWindowsRequestCapture) {
948 WindowTreeSetup setup;
949 Window* root = setup.GetFirstRoot();
950 Window* child = setup.client()->NewWindow();
951 child->SetVisible(true);
952 root->AddChild(child);
953
954 root->SetCapture();
955 EXPECT_TRUE(root->HasCapture());
956 uint32_t change_id1;
957 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
958
959 child->SetCapture();
960 EXPECT_TRUE(child->HasCapture());
961 EXPECT_FALSE(root->HasCapture());
962
963 uint32_t change_id2;
964 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id2));
965
966 setup.window_tree_client()->OnChangeCompleted(change_id1, true);
967 EXPECT_FALSE(root->HasCapture());
968 EXPECT_TRUE(child->HasCapture());
969
970 setup.window_tree_client()->OnChangeCompleted(change_id2, false);
971 EXPECT_FALSE(child->HasCapture());
972 EXPECT_TRUE(root->HasCapture());
973
974 setup.window_tree_client()->OnCaptureChanged(0, server_id(root));
975 EXPECT_FALSE(root->HasCapture());
976 }
977
978 TEST_F(WindowTreeClientTest, WindowDestroyedWhileTransientChildHasCapture) {
979 WindowTreeSetup setup;
980 Window* root = setup.GetFirstRoot();
981 Window* transient_parent = setup.client()->NewWindow();
982 Window* transient_child = setup.client()->NewWindow();
983 transient_parent->SetVisible(true);
984 transient_child->SetVisible(true);
985 root->AddChild(transient_parent);
986 root->AddChild(transient_child);
987
988 transient_parent->AddTransientWindow(transient_child);
989
990 WindowTracker tracker;
991 tracker.Add(transient_parent);
992 tracker.Add(transient_child);
993 // Request a capture on the transient child, then destroy the transient
994 // parent. That will destroy both windows, and should reset the capture window
995 // correctly.
996 transient_child->SetCapture();
997 transient_parent->Destroy();
998 EXPECT_TRUE(tracker.windows().empty());
999
1000 // Create a new Window, and attempt to place capture on that.
1001 Window* child = setup.client()->NewWindow();
1002 child->SetVisible(true);
1003 root->AddChild(child);
1004 child->SetCapture();
1005 EXPECT_TRUE(child->HasCapture());
1006 }
1007
1008 namespace {
1009
1010 class CaptureRecorder : public WindowTreeClientObserver {
1011 public:
1012 explicit CaptureRecorder(WindowTreeClient* tree_client)
1013 : tree_client_(tree_client) {
1014 tree_client_->AddObserver(this);
1015 }
1016
1017 ~CaptureRecorder() override { tree_client_->RemoveObserver(this); }
1018
1019 void reset_capture_captured_count() { capture_changed_count_ = 0; }
1020 int capture_changed_count() const { return capture_changed_count_; }
1021 int last_gained_capture_window_id() const {
1022 return last_gained_capture_window_id_;
1023 }
1024 int last_lost_capture_window_id() const {
1025 return last_lost_capture_window_id_;
1026 }
1027
1028 // WindowTreeClientObserver:
1029 void OnWindowTreeCaptureChanged(Window* gained_capture,
1030 Window* lost_capture) override {
1031 capture_changed_count_++;
1032 last_gained_capture_window_id_ =
1033 gained_capture ? gained_capture->local_id() : 0;
1034 last_lost_capture_window_id_ = lost_capture ? lost_capture->local_id() : 0;
1035 }
1036
1037 private:
1038 WindowTreeClient* tree_client_;
1039 int capture_changed_count_ = 0;
1040 int last_gained_capture_window_id_ = 0;
1041 int last_lost_capture_window_id_ = 0;
1042
1043 DISALLOW_COPY_AND_ASSIGN(CaptureRecorder);
1044 };
1045
1046 } // namespace
1047
1048 TEST_F(WindowTreeClientTest, OnWindowTreeCaptureChanged) {
1049 WindowTreeSetup setup;
1050 CaptureRecorder capture_recorder(setup.client());
1051 Window* root = setup.GetFirstRoot();
1052 Window* child1 = setup.client()->NewWindow();
1053 const int child1_id = 1;
1054 child1->set_local_id(child1_id);
1055 child1->SetVisible(true);
1056 root->AddChild(child1);
1057 Window* child2 = setup.client()->NewWindow();
1058 const int child2_id = 2;
1059 child2->set_local_id(child2_id);
1060 child2->SetVisible(true);
1061 root->AddChild(child2);
1062
1063 EXPECT_EQ(0, capture_recorder.capture_changed_count());
1064 // Give capture to child1 and ensure everyone is notified correctly.
1065 child1->SetCapture();
1066 uint32_t change_id;
1067 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
1068 setup.window_tree_client()->OnChangeCompleted(change_id, true);
1069 EXPECT_EQ(1, capture_recorder.capture_changed_count());
1070 EXPECT_EQ(child1_id, capture_recorder.last_gained_capture_window_id());
1071 EXPECT_EQ(0, capture_recorder.last_lost_capture_window_id());
1072 capture_recorder.reset_capture_captured_count();
1073
1074 // Deleting a window with capture should notify observers as well.
1075 child1->Destroy();
1076 child1 = nullptr;
1077 EXPECT_EQ(1, capture_recorder.capture_changed_count());
1078 EXPECT_EQ(0, capture_recorder.last_gained_capture_window_id());
1079 EXPECT_EQ(child1_id, capture_recorder.last_lost_capture_window_id());
1080 capture_recorder.reset_capture_captured_count();
1081
1082 // Changes originating from server should notify observers too.
1083 WindowTreeClientPrivate(setup.client()).CallOnCaptureChanged(child2, nullptr);
1084 EXPECT_EQ(1, capture_recorder.capture_changed_count());
1085 EXPECT_EQ(child2_id, capture_recorder.last_gained_capture_window_id());
1086 EXPECT_EQ(0, capture_recorder.last_lost_capture_window_id());
1087 capture_recorder.reset_capture_captured_count();
1088 }
1089
1090 } // namespace ui
OLDNEW
« no previous file with comments | « services/ui/public/cpp/tests/window_tree_client_private.cc ('k') | services/ui/public/cpp/tests/window_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698