Automated Commit: Committing new LKGM version 7479.0.0 for chromeos.
[chromium-blink-merge.git] / ui / views / cocoa / bridged_native_widget_unittest.mm
blob3f0d110643b817a4b8e6aeb20a4ec666d68d768d
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.
5 #import "ui/views/cocoa/bridged_native_widget.h"
7 #import <Cocoa/Cocoa.h>
9 #import "base/mac/foundation_util.h"
10 #import "base/mac/mac_util.h"
11 #import "base/mac/sdk_forward_declarations.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #import "testing/gtest_mac.h"
17 #import "ui/base/cocoa/window_size_constants.h"
18 #include "ui/base/ime/input_method.h"
19 #import "ui/gfx/test/ui_cocoa_test_helper.h"
20 #import "ui/views/cocoa/bridged_content_view.h"
21 #import "ui/views/cocoa/native_widget_mac_nswindow.h"
22 #import "ui/views/cocoa/views_nswindow_delegate.h"
23 #include "ui/views/controls/textfield/textfield.h"
24 #include "ui/views/view.h"
25 #include "ui/views/widget/native_widget_mac.h"
26 #include "ui/views/widget/root_view.h"
27 #include "ui/views/widget/widget.h"
28 #include "ui/views/widget/widget_observer.h"
30 using base::ASCIIToUTF16;
31 using base::SysNSStringToUTF8;
32 using base::SysNSStringToUTF16;
33 using base::SysUTF8ToNSString;
35 #define EXPECT_EQ_RANGE(a, b)        \
36   EXPECT_EQ(a.location, b.location); \
37   EXPECT_EQ(a.length, b.length);
39 namespace {
41 // Empty range shortcut for readibility.
42 NSRange EmptyRange() {
43   return NSMakeRange(NSNotFound, 0);
46 }  // namespace
48 // Class to override -[NSWindow toggleFullScreen:] to a no-op. This simulates
49 // NSWindow's behavior when attempting to toggle fullscreen state again, when
50 // the last attempt failed but Cocoa has not yet sent
51 // windowDidFailToEnterFullScreen:.
52 @interface BridgedNativeWidgetTestFullScreenWindow : NativeWidgetMacNSWindow {
53  @private
54   int ignoredToggleFullScreenCount_;
56 @property(readonly, nonatomic) int ignoredToggleFullScreenCount;
57 @end
59 @implementation BridgedNativeWidgetTestFullScreenWindow
61 @synthesize ignoredToggleFullScreenCount = ignoredToggleFullScreenCount_;
63 - (void)toggleFullScreen:(id)sender {
64   ++ignoredToggleFullScreenCount_;
67 @end
69 namespace views {
70 namespace test {
72 // Provides the |parent| argument to construct a BridgedNativeWidget.
73 class MockNativeWidgetMac : public NativeWidgetMac {
74  public:
75   MockNativeWidgetMac(Widget* delegate) : NativeWidgetMac(delegate) {}
77   // Expose a reference, so that it can be reset() independently.
78   scoped_ptr<BridgedNativeWidget>& bridge() {
79     return bridge_;
80   }
82   // internal::NativeWidgetPrivate:
83   void InitNativeWidget(const Widget::InitParams& params) override {
84     ownership_ = params.ownership;
86     // Usually the bridge gets initialized here. It is skipped to run extra
87     // checks in tests, and so that a second window isn't created.
88     delegate()->OnNativeWidgetCreated(true);
90     // To allow events to dispatch to a view, it needs a way to get focus.
91     bridge_->SetFocusManager(GetWidget()->GetFocusManager());
92   }
94   void ReorderNativeViews() override {
95     // Called via Widget::Init to set the content view. No-op in these tests.
96   }
98  private:
99   DISALLOW_COPY_AND_ASSIGN(MockNativeWidgetMac);
102 // Helper test base to construct a BridgedNativeWidget with a valid parent.
103 class BridgedNativeWidgetTestBase : public ui::CocoaTest {
104  public:
105   BridgedNativeWidgetTestBase()
106       : widget_(new Widget),
107         native_widget_mac_(new MockNativeWidgetMac(widget_.get())) {
108   }
110   scoped_ptr<BridgedNativeWidget>& bridge() {
111     return native_widget_mac_->bridge();
112   }
114   // Overridden from testing::Test:
115   void SetUp() override {
116     ui::CocoaTest::SetUp();
118     init_params_.native_widget = native_widget_mac_;
120     // Use a frameless window, otherwise Widget will try to center the window
121     // before the tests covering the Init() flow are ready to do that.
122     init_params_.type = Widget::InitParams::TYPE_WINDOW_FRAMELESS;
124     // To control the lifetime without an actual window that must be closed,
125     // tests in this file need to use WIDGET_OWNS_NATIVE_WIDGET.
126     init_params_.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
128     // Opacity defaults to "infer" which is usually updated by ViewsDelegate.
129     init_params_.opacity = Widget::InitParams::OPAQUE_WINDOW;
131     native_widget_mac_->GetWidget()->Init(init_params_);
132   }
134  protected:
135   scoped_ptr<Widget> widget_;
136   MockNativeWidgetMac* native_widget_mac_;  // Weak. Owned by |widget_|.
138   // Make the InitParams available to tests to cover initialization codepaths.
139   Widget::InitParams init_params_;
142 class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase {
143  public:
144   BridgedNativeWidgetTest();
145   ~BridgedNativeWidgetTest() override;
147   // Install a textfield in the view hierarchy and make it the text input
148   // client.
149   void InstallTextField(const std::string& text);
151   // Returns the current text as std::string.
152   std::string GetText();
154   // testing::Test:
155   void SetUp() override;
156   void TearDown() override;
158  protected:
159   scoped_ptr<views::View> view_;
160   scoped_ptr<BridgedNativeWidget> bridge_;
161   BridgedContentView* ns_view_;  // Weak. Owned by bridge_.
162   base::MessageLoopForUI message_loop_;
164  private:
165   DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTest);
168 BridgedNativeWidgetTest::BridgedNativeWidgetTest() {
171 BridgedNativeWidgetTest::~BridgedNativeWidgetTest() {
174 void BridgedNativeWidgetTest::InstallTextField(const std::string& text) {
175   Textfield* textfield = new Textfield();
176   textfield->SetText(ASCIIToUTF16(text));
177   view_->AddChildView(textfield);
179   // Request focus so the InputMethod can dispatch events to the RootView, and
180   // have them delivered to the textfield. Note that focusing a textfield
181   // schedules a task to flash the cursor, so this requires |message_loop_|.
182   textfield->RequestFocus();
184   [ns_view_ setTextInputClient:textfield];
187 std::string BridgedNativeWidgetTest::GetText() {
188   NSRange range = NSMakeRange(0, NSUIntegerMax);
189   NSAttributedString* text =
190       [ns_view_ attributedSubstringForProposedRange:range actualRange:NULL];
191   return SysNSStringToUTF8([text string]);
194 void BridgedNativeWidgetTest::SetUp() {
195   BridgedNativeWidgetTestBase::SetUp();
197   view_.reset(new views::internal::RootView(widget_.get()));
198   base::scoped_nsobject<NSWindow> window([test_window() retain]);
200   // BridgedNativeWidget expects to be initialized with a hidden (deferred)
201   // window.
202   [window orderOut:nil];
203   EXPECT_FALSE([window delegate]);
204   bridge()->Init(window, init_params_);
206   // The delegate should exist before setting the root view.
207   EXPECT_TRUE([window delegate]);
208   bridge()->SetRootView(view_.get());
209   ns_view_ = bridge()->ns_view();
211   // Pretend it has been shown via NativeWidgetMac::Show().
212   [window orderFront:nil];
213   [test_window() makePretendKeyWindowAndSetFirstResponder:bridge()->ns_view()];
216 void BridgedNativeWidgetTest::TearDown() {
217   view_.reset();
218   BridgedNativeWidgetTestBase::TearDown();
221 // The TEST_VIEW macro expects the view it's testing to have a superview. In
222 // these tests, the NSView bridge is a contentView, at the root. These mimic
223 // what TEST_VIEW usually does.
224 TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewAddRemove) {
225   base::scoped_nsobject<BridgedContentView> view([bridge()->ns_view() retain]);
226   EXPECT_NSEQ([test_window() contentView], view);
227   EXPECT_NSEQ(test_window(), [view window]);
229   // The superview of a contentView is an NSNextStepFrame.
230   EXPECT_TRUE([view superview]);
231   EXPECT_TRUE([view hostedView]);
233   // Ensure the tracking area to propagate mouseMoved: events to the RootView is
234   // installed.
235   EXPECT_EQ(1u, [[view trackingAreas] count]);
237   // Destroying the C++ bridge should remove references to any C++ objects in
238   // the ObjectiveC object, and remove it from the hierarchy.
239   bridge().reset();
240   EXPECT_FALSE([view hostedView]);
241   EXPECT_FALSE([view superview]);
242   EXPECT_FALSE([view window]);
243   EXPECT_EQ(0u, [[view trackingAreas] count]);
244   EXPECT_FALSE([test_window() contentView]);
245   EXPECT_FALSE([test_window() delegate]);
248 TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewDisplay) {
249   [bridge()->ns_view() display];
252 // Test that resizing the window resizes the root view appropriately.
253 TEST_F(BridgedNativeWidgetTest, ViewSizeTracksWindow) {
254   const int kTestNewWidth = 400;
255   const int kTestNewHeight = 300;
257   // |test_window()| is borderless, so these should align.
258   NSSize window_size = [test_window() frame].size;
259   EXPECT_EQ(view_->width(), static_cast<int>(window_size.width));
260   EXPECT_EQ(view_->height(), static_cast<int>(window_size.height));
262   // Make sure a resize actually occurs.
263   EXPECT_NE(kTestNewWidth, view_->width());
264   EXPECT_NE(kTestNewHeight, view_->height());
266   [test_window() setFrame:NSMakeRect(0, 0, kTestNewWidth, kTestNewHeight)
267                   display:NO];
268   EXPECT_EQ(kTestNewWidth, view_->width());
269   EXPECT_EQ(kTestNewHeight, view_->height());
272 TEST_F(BridgedNativeWidgetTest, GetInputMethodShouldNotReturnNull) {
273   EXPECT_TRUE(bridge()->GetInputMethod());
276 // A simpler test harness for testing initialization flows.
277 class BridgedNativeWidgetInitTest : public BridgedNativeWidgetTestBase {
278  public:
279   BridgedNativeWidgetInitTest() {}
281   // Prepares a new |window_| and |widget_| for a call to PerformInit().
282   void CreateNewWidgetToInit(NSUInteger style_mask) {
283     window_.reset(
284         [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
285                                     styleMask:style_mask
286                                       backing:NSBackingStoreBuffered
287                                         defer:NO]);
288     [window_ setReleasedWhenClosed:NO];  // Owned by scoped_nsobject.
289     widget_.reset(new Widget);
290     native_widget_mac_ = new MockNativeWidgetMac(widget_.get());
291     init_params_.native_widget = native_widget_mac_;
292   }
294   void PerformInit() {
295     widget_->Init(init_params_);
296     bridge()->Init(window_, init_params_);
297   }
299  protected:
300   base::scoped_nsobject<NSWindow> window_;
302  private:
303   DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetInitTest);
306 // Test that BridgedNativeWidget remains sane if Init() is never called.
307 TEST_F(BridgedNativeWidgetInitTest, InitNotCalled) {
308   EXPECT_FALSE(bridge()->ns_view());
309   EXPECT_FALSE(bridge()->ns_window());
310   bridge().reset();
313 // Tests the shadow type given in InitParams.
314 TEST_F(BridgedNativeWidgetInitTest, ShadowType) {
315   // Verify Widget::InitParam defaults and arguments added from SetUp().
316   EXPECT_EQ(Widget::InitParams::TYPE_WINDOW_FRAMELESS, init_params_.type);
317   EXPECT_EQ(Widget::InitParams::OPAQUE_WINDOW, init_params_.opacity);
318   EXPECT_EQ(Widget::InitParams::SHADOW_TYPE_DEFAULT, init_params_.shadow_type);
320   CreateNewWidgetToInit(NSBorderlessWindowMask);
321   EXPECT_FALSE([window_ hasShadow]);  // Default for NSBorderlessWindowMask.
322   PerformInit();
324   // Borderless is 0, so isn't really a mask. Check that nothing is set.
325   EXPECT_EQ(NSBorderlessWindowMask, [window_ styleMask]);
326   EXPECT_TRUE([window_ hasShadow]);  // SHADOW_TYPE_DEFAULT means a shadow.
328   CreateNewWidgetToInit(NSBorderlessWindowMask);
329   init_params_.shadow_type = Widget::InitParams::SHADOW_TYPE_NONE;
330   PerformInit();
331   EXPECT_FALSE([window_ hasShadow]);  // Preserves lack of shadow.
333   // Default for Widget::InitParams::TYPE_WINDOW.
334   NSUInteger kBorderedMask =
335       NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask |
336       NSResizableWindowMask | NSTexturedBackgroundWindowMask;
337   CreateNewWidgetToInit(kBorderedMask);
338   EXPECT_TRUE([window_ hasShadow]);  // Default for non-borderless.
339   PerformInit();
340   EXPECT_FALSE([window_ hasShadow]);  // SHADOW_TYPE_NONE removes shadow.
342   init_params_.shadow_type = Widget::InitParams::SHADOW_TYPE_DEFAULT;
343   CreateNewWidgetToInit(kBorderedMask);
344   PerformInit();
345   EXPECT_TRUE([window_ hasShadow]);  // Preserves shadow.
347   window_.reset();
348   widget_.reset();
351 // Test getting complete string using text input protocol.
352 TEST_F(BridgedNativeWidgetTest, TextInput_GetCompleteString) {
353   const std::string kTestString = "foo bar baz";
354   InstallTextField(kTestString);
356   NSRange range = NSMakeRange(0, kTestString.size());
357   NSRange actual_range;
358   NSAttributedString* text =
359       [ns_view_ attributedSubstringForProposedRange:range
360                                         actualRange:&actual_range];
361   EXPECT_EQ(kTestString, SysNSStringToUTF8([text string]));
362   EXPECT_EQ_RANGE(range, actual_range);
365 // Test getting middle substring using text input protocol.
366 TEST_F(BridgedNativeWidgetTest, TextInput_GetMiddleSubstring) {
367   const std::string kTestString = "foo bar baz";
368   InstallTextField(kTestString);
370   NSRange range = NSMakeRange(4, 3);
371   NSRange actual_range;
372   NSAttributedString* text =
373       [ns_view_ attributedSubstringForProposedRange:range
374                                         actualRange:&actual_range];
375   EXPECT_EQ("bar", SysNSStringToUTF8([text string]));
376   EXPECT_EQ_RANGE(range, actual_range);
379 // Test getting ending substring using text input protocol.
380 TEST_F(BridgedNativeWidgetTest, TextInput_GetEndingSubstring) {
381   const std::string kTestString = "foo bar baz";
382   InstallTextField(kTestString);
384   NSRange range = NSMakeRange(8, 100);
385   NSRange actual_range;
386   NSAttributedString* text =
387       [ns_view_ attributedSubstringForProposedRange:range
388                                         actualRange:&actual_range];
389   EXPECT_EQ("baz", SysNSStringToUTF8([text string]));
390   EXPECT_EQ(range.location, actual_range.location);
391   EXPECT_EQ(3U, actual_range.length);
394 // Test getting empty substring using text input protocol.
395 TEST_F(BridgedNativeWidgetTest, TextInput_GetEmptySubstring) {
396   const std::string kTestString = "foo bar baz";
397   InstallTextField(kTestString);
399   NSRange range = EmptyRange();
400   NSRange actual_range;
401   NSAttributedString* text =
402       [ns_view_ attributedSubstringForProposedRange:range
403                                         actualRange:&actual_range];
404   EXPECT_EQ("", SysNSStringToUTF8([text string]));
405   EXPECT_EQ_RANGE(range, actual_range);
408 // Test inserting text using text input protocol.
409 TEST_F(BridgedNativeWidgetTest, TextInput_InsertText) {
410   const std::string kTestString = "foo";
411   InstallTextField(kTestString);
413   [ns_view_ insertText:SysUTF8ToNSString(kTestString)
414       replacementRange:EmptyRange()];
415   gfx::Range range(0, kTestString.size());
416   base::string16 text;
417   EXPECT_TRUE([ns_view_ textInputClient]->GetTextFromRange(range, &text));
418   EXPECT_EQ(ASCIIToUTF16(kTestString), text);
421 // Test replacing text using text input protocol.
422 TEST_F(BridgedNativeWidgetTest, TextInput_ReplaceText) {
423   const std::string kTestString = "foo bar";
424   InstallTextField(kTestString);
426   [ns_view_ insertText:@"baz" replacementRange:NSMakeRange(4, 3)];
427   EXPECT_EQ("foo baz", GetText());
430 // Test IME composition using text input protocol.
431 TEST_F(BridgedNativeWidgetTest, TextInput_Compose) {
432   const std::string kTestString = "foo ";
433   InstallTextField(kTestString);
435   EXPECT_FALSE([ns_view_ hasMarkedText]);
436   EXPECT_EQ_RANGE(EmptyRange(), [ns_view_ markedRange]);
438   // Start composition.
439   NSString* compositionText = @"bar";
440   NSUInteger compositionLength = [compositionText length];
441   [ns_view_ setMarkedText:compositionText
442             selectedRange:NSMakeRange(0, 2)
443          replacementRange:EmptyRange()];
444   EXPECT_TRUE([ns_view_ hasMarkedText]);
445   EXPECT_EQ_RANGE(NSMakeRange(kTestString.size(), compositionLength),
446                   [ns_view_ markedRange]);
447   EXPECT_EQ_RANGE(NSMakeRange(kTestString.size(), 2), [ns_view_ selectedRange]);
449   // Confirm composition.
450   [ns_view_ unmarkText];
451   EXPECT_FALSE([ns_view_ hasMarkedText]);
452   EXPECT_EQ_RANGE(EmptyRange(), [ns_view_ markedRange]);
453   EXPECT_EQ("foo bar", GetText());
454   EXPECT_EQ_RANGE(NSMakeRange(GetText().size(), 0), [ns_view_ selectedRange]);
457 // Test moving the caret left and right using text input protocol.
458 TEST_F(BridgedNativeWidgetTest, TextInput_MoveLeftRight) {
459   InstallTextField("foo");
460   EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]);
462   // Move right not allowed, out of range.
463   [ns_view_ doCommandBySelector:@selector(moveRight:)];
464   EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]);
466   // Move left.
467   [ns_view_ doCommandBySelector:@selector(moveLeft:)];
468   EXPECT_EQ_RANGE(NSMakeRange(2, 0), [ns_view_ selectedRange]);
470   // Move right.
471   [ns_view_ doCommandBySelector:@selector(moveRight:)];
472   EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]);
475 // Test backward delete using text input protocol.
476 TEST_F(BridgedNativeWidgetTest, TextInput_DeleteBackward) {
477   InstallTextField("a");
478   EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]);
480   // Delete one character.
481   [ns_view_ doCommandBySelector:@selector(deleteBackward:)];
482   EXPECT_EQ("", GetText());
483   EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]);
485   // Try to delete again on an empty string.
486   [ns_view_ doCommandBySelector:@selector(deleteBackward:)];
487   EXPECT_EQ("", GetText());
488   EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]);
491 // Test forward delete using text input protocol.
492 TEST_F(BridgedNativeWidgetTest, TextInput_DeleteForward) {
493   InstallTextField("a");
494   EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]);
496   // At the end of the string, can't delete forward.
497   [ns_view_ doCommandBySelector:@selector(deleteForward:)];
498   EXPECT_EQ("a", GetText());
499   EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]);
501   // Should succeed after moving left first.
502   [ns_view_ doCommandBySelector:@selector(moveLeft:)];
503   [ns_view_ doCommandBySelector:@selector(deleteForward:)];
504   EXPECT_EQ("", GetText());
505   EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]);
508 typedef BridgedNativeWidgetTestBase BridgedNativeWidgetSimulateFullscreenTest;
510 // Simulate the notifications that AppKit would send out if a fullscreen
511 // operation begins, and then fails and must abort. This notification sequence
512 // was determined by posting delayed tasks to toggle fullscreen state and then
513 // mashing Ctrl+Left/Right to keep OSX in a transition between Spaces to cause
514 // the fullscreen transition to fail.
515 TEST_F(BridgedNativeWidgetSimulateFullscreenTest, FailToEnterAndExit) {
516   if (base::mac::IsOSSnowLeopard())
517     return;
519   base::scoped_nsobject<NSWindow> owned_window(
520       [[BridgedNativeWidgetTestFullScreenWindow alloc]
521           initWithContentRect:NSMakeRect(50, 50, 400, 300)
522                     styleMask:NSBorderlessWindowMask
523                       backing:NSBackingStoreBuffered
524                         defer:NO]);
525   [owned_window setReleasedWhenClosed:NO];  // Owned by scoped_nsobject.
526   bridge()->Init(owned_window, init_params_);  // Transfers ownership.
528   BridgedNativeWidgetTestFullScreenWindow* window =
529       base::mac::ObjCCastStrict<BridgedNativeWidgetTestFullScreenWindow>(
530           widget_->GetNativeWindow());
531   widget_->Show();
533   NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
535   EXPECT_FALSE(bridge()->target_fullscreen_state());
537   // Simulate an initial toggleFullScreen: (user- or Widget-initiated).
538   [center postNotificationName:NSWindowWillEnterFullScreenNotification
539                         object:window];
541   // On a failure, Cocoa starts by sending an unexpected *exit* fullscreen, and
542   // BridgedNativeWidget will think it's just a delayed transition and try to go
543   // back into fullscreen but get ignored by Cocoa.
544   EXPECT_EQ(0, [window ignoredToggleFullScreenCount]);
545   EXPECT_TRUE(bridge()->target_fullscreen_state());
546   [center postNotificationName:NSWindowDidExitFullScreenNotification
547                         object:window];
548   EXPECT_EQ(1, [window ignoredToggleFullScreenCount]);
549   EXPECT_FALSE(bridge()->target_fullscreen_state());
551   // Cocoa follows up with a failure message sent to the NSWindowDelegate (there
552   // is no equivalent notification for failure). Called via id so that this
553   // compiles on 10.6.
554   ViewsNSWindowDelegate* window_delegate =
555       base::mac::ObjCCast<ViewsNSWindowDelegate>([window delegate]);
556   [window_delegate windowDidFailToEnterFullScreen:window];
557   EXPECT_FALSE(bridge()->target_fullscreen_state());
559   // Now perform a successful fullscreen operation.
560   [center postNotificationName:NSWindowWillEnterFullScreenNotification
561                         object:window];
562   EXPECT_TRUE(bridge()->target_fullscreen_state());
563   [center postNotificationName:NSWindowDidEnterFullScreenNotification
564                         object:window];
565   EXPECT_TRUE(bridge()->target_fullscreen_state());
567   // And try to get out.
568   [center postNotificationName:NSWindowWillExitFullScreenNotification
569                         object:window];
570   EXPECT_FALSE(bridge()->target_fullscreen_state());
572   // On a failure, Cocoa sends a failure message, but then just dumps the window
573   // out of fullscreen anyway (in that order).
574   [window_delegate windowDidFailToExitFullScreen:window];
575   EXPECT_FALSE(bridge()->target_fullscreen_state());
576   [center postNotificationName:NSWindowDidExitFullScreenNotification
577                         object:window];
578   EXPECT_EQ(1, [window ignoredToggleFullScreenCount]);  // No change.
579   EXPECT_FALSE(bridge()->target_fullscreen_state());
581   widget_->CloseNow();
584 }  // namespace test
585 }  // namespace views