OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/cocoa/cocoa_test_helper.h" | 5 #import "chrome/browser/cocoa/cocoa_test_helper.h" |
| 6 #import "base/logging.h" |
6 | 7 |
7 @implementation CocoaTestHelperWindow | 8 @implementation CocoaTestHelperWindow |
8 | 9 |
9 - (id)initWithContentRect:(NSRect)contentRect { | 10 - (id)initWithContentRect:(NSRect)contentRect { |
10 return [self initWithContentRect:contentRect | 11 return [self initWithContentRect:contentRect |
11 styleMask:NSBorderlessWindowMask | 12 styleMask:NSBorderlessWindowMask |
12 backing:NSBackingStoreBuffered | 13 backing:NSBackingStoreBuffered |
13 defer:NO]; | 14 defer:NO]; |
14 } | 15 } |
15 | 16 |
16 - (id)init { | 17 - (id)init { |
17 return [self initWithContentRect:NSMakeRect(0, 0, 800, 600)]; | 18 return [self initWithContentRect:NSMakeRect(0, 0, 800, 600)]; |
18 } | 19 } |
19 | 20 |
| 21 - (void)dealloc { |
| 22 // Just a good place to put breakpoints when having problems with |
| 23 // unittests and CocoaTestHelperWindow. |
| 24 [super dealloc]; |
| 25 } |
| 26 |
| 27 - (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder { |
| 28 EXPECT_TRUE([self makeFirstResponder:responder]); |
| 29 [self setPretendIsKeyWindow:YES]; |
| 30 } |
| 31 |
| 32 - (void)clearPretendKeyWindowAndFirstResponder { |
| 33 [self setPretendIsKeyWindow:NO]; |
| 34 EXPECT_TRUE([self makeFirstResponder:NSApp]); |
| 35 } |
| 36 |
20 - (void)setPretendIsKeyWindow:(BOOL)flag { | 37 - (void)setPretendIsKeyWindow:(BOOL)flag { |
21 pretendIsKeyWindow_ = flag; | 38 pretendIsKeyWindow_ = flag; |
22 } | 39 } |
23 | 40 |
24 - (BOOL)isKeyWindow { | 41 - (BOOL)isKeyWindow { |
25 return pretendIsKeyWindow_; | 42 return pretendIsKeyWindow_; |
26 } | 43 } |
27 | 44 |
28 @end | 45 @end |
| 46 |
| 47 CocoaTest::CocoaTest() : called_tear_down_(false), test_window_(nil) { |
| 48 BootstrapCocoa(); |
| 49 // Set the duration of AppKit-evaluated animations (such as frame changes) |
| 50 // to zero for testing purposes. That way they take effect immediately. |
| 51 [[NSAnimationContext currentContext] setDuration:0.0]; |
| 52 // Collect the list of windows that were open when the test started so |
| 53 // that we don't wait for them to close in TearDown. Has to be done |
| 54 // after BootstrapCocoa is called. |
| 55 initial_windows_ = ApplicationWindows(); |
| 56 } |
| 57 |
| 58 CocoaTest::~CocoaTest() { |
| 59 // Must call CocoaTest's teardown from your overrides. |
| 60 DCHECK(called_tear_down_); |
| 61 } |
| 62 |
| 63 void CocoaTest::BootstrapCocoa() { |
| 64 // Look in the framework bundle for resources. |
| 65 FilePath path; |
| 66 PathService::Get(base::DIR_EXE, &path); |
| 67 path = path.Append(chrome::kFrameworkName); |
| 68 mac_util::SetOverrideAppBundlePath(path); |
| 69 |
| 70 // Bootstrap Cocoa. It's very unhappy without this. |
| 71 [NSApplication sharedApplication]; |
| 72 } |
| 73 |
| 74 void CocoaTest::TearDown() { |
| 75 called_tear_down_ = true; |
| 76 // Call close on our test_window to clean it up if one was opened. |
| 77 [test_window_ close]; |
| 78 test_window_ = nil; |
| 79 |
| 80 // Recycle the pool to clean up any stuff that was put on the |
| 81 // autorelease pool due to window or windowcontroller closures. |
| 82 // Note that many controls (NSTextFields, NSComboboxes etc) may call |
| 83 // performSelector:withDelay: to clean up drag handlers and other things. |
| 84 // We must spin the event loop a bit to make sure that everything gets cleaned |
| 85 // up correctly. We will wait up to one second for windows to clean themselves |
| 86 // up (normally only takes one to two loops through the event loop). |
| 87 // Radar 5851458 "Closing a window with a NSTextView in it should get rid of |
| 88 // it immediately" |
| 89 pool_.Recycle(); |
| 90 NSDate *start_date = [NSDate date]; |
| 91 const std::vector<NSWindow*> windows_waiting(ApplicationWindows()); |
| 92 |
| 93 bool loop = windows_waiting.size() > 0; |
| 94 while (loop) { |
| 95 { |
| 96 // Need an autorelease pool to wrap our event loop. |
| 97 base::ScopedNSAutoreleasePool pool; |
| 98 NSEvent *next_event = [NSApp nextEventMatchingMask:NSAnyEventMask |
| 99 untilDate:nil |
| 100 inMode:NSDefaultRunLoopMode |
| 101 dequeue:YES]; |
| 102 [NSApp sendEvent:next_event]; |
| 103 [NSApp updateWindows]; |
| 104 } |
| 105 // Check the windows after we have released the event loop pool so that |
| 106 // all retains are cleaned up. |
| 107 const std::vector<NSWindow*> current_windows(ApplicationWindows()); |
| 108 std::vector<NSWindow*> windows_left; |
| 109 std::set_difference(current_windows.begin(), |
| 110 current_windows.end(), |
| 111 initial_windows_.begin(), |
| 112 initial_windows_.end(), |
| 113 inserter(windows_left, windows_left.begin())); |
| 114 |
| 115 if (windows_left.size() == 0) { |
| 116 // All our windows are closed. |
| 117 break; |
| 118 } |
| 119 if ([start_date timeIntervalSinceNow] < -1.0) { |
| 120 // Took us over a second to shut down, and windows still exist. |
| 121 // Log a failure and continue. |
| 122 EXPECT_EQ(windows_left.size(), 0U); |
| 123 for (size_t i = 0; i < windows_left.size(); ++i) { |
| 124 const char* desc = [[windows_left[i] description] UTF8String]; |
| 125 LOG(WARNING) << "Didn't close window " << desc; |
| 126 } |
| 127 break; |
| 128 } |
| 129 } |
| 130 PlatformTest::TearDown(); |
| 131 } |
| 132 |
| 133 std::vector<NSWindow*> CocoaTest::ApplicationWindows() { |
| 134 // This must NOT retain the windows it is returning. |
| 135 std::vector<NSWindow*> windows; |
| 136 // Must create a pool here because [NSApp windows] has created an array |
| 137 // with retains on all the windows in it. |
| 138 base::ScopedNSAutoreleasePool pool; |
| 139 NSArray *appWindows = [NSApp windows]; |
| 140 for (NSWindow *window in appWindows) { |
| 141 windows.push_back(window); |
| 142 } |
| 143 return windows; |
| 144 } |
| 145 |
| 146 CocoaTestHelperWindow* CocoaTest::test_window() { |
| 147 if (!test_window_) { |
| 148 test_window_ = [[CocoaTestHelperWindow alloc] init]; |
| 149 if (DebugUtil::BeingDebugged()) { |
| 150 [test_window_ orderFront:nil]; |
| 151 } else { |
| 152 [test_window_ orderBack:nil]; |
| 153 } |
| 154 } |
| 155 return test_window_; |
| 156 } |
OLD | NEW |