1 // Copyright (c) 2011 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 #ifndef CHROME_BROWSER_UI_COCOA_COCOA_TEST_HELPER_H_ 6 #define CHROME_BROWSER_UI_COCOA_COCOA_TEST_HELPER_H_ 7 #pragma once 8 9 #import <Cocoa/Cocoa.h> 10 11 #include "base/path_service.h" 12 #import "base/mac/scoped_nsautorelease_pool.h" 13 #import "base/memory/scoped_nsobject.h" 14 #include "chrome/common/chrome_constants.h" 15 #import "content/common/chrome_application_mac.h" 16 #include "testing/platform_test.h" 17 18 // Background windows normally will not display things such as focus 19 // rings. This class allows -isKeyWindow to be manipulated to test 20 // such things. 21 @interface CocoaTestHelperWindow : NSWindow { 22 @private 23 BOOL pretendIsKeyWindow_; 24 } 25 26 // Init a borderless non-deferred window with a backing store. 27 - (id)initWithContentRect:(NSRect)contentRect; 28 29 // Init with a default frame. 30 - (id)init; 31 32 // Sets the responder passed in as first responder, and sets the window 33 // so that it will return "YES" if asked if it key window. It does not actually 34 // make the window key. 35 - (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder; 36 37 // Clears the first responder duty for the window and returns the window 38 // to being non-key. 39 - (void)clearPretendKeyWindowAndFirstResponder; 40 41 // Set value to return for -isKeyWindow. 42 - (void)setPretendIsKeyWindow:(BOOL)isKeyWindow; 43 44 - (BOOL)isKeyWindow; 45 46 @end 47 48 // A test class that all tests that depend on AppKit should inherit from. 49 // Sets up NSApplication and paths correctly, and makes sure that any windows 50 // created in the test are closed down properly by the test. If you need to 51 // inherit from a different test class, but need to set up the AppKit runtime 52 // environment, you can call BootstrapCocoa directly from your test class. You 53 // will have to deal with windows on your own though. 54 class CocoaTest : public PlatformTest { 55 public: 56 // Sets up AppKit and paths correctly for unit tests. If you can't inherit 57 // from CocoaTest but are going to be using any AppKit features directly, 58 // or indirectly, you should be calling this from the c'tor or SetUp methods 59 // of your test class. 60 static void BootstrapCocoa(); 61 62 CocoaTest(); 63 virtual ~CocoaTest(); 64 65 // Must be called by subclasses that override TearDown. We verify that it 66 // is called in our destructor. Takes care of making sure that all windows 67 // are closed off correctly. If your tests open windows, they must be sure 68 // to close them before CocoaTest::TearDown is called. A standard way of doing 69 // this would be to create them in SetUp (after calling CocoaTest::Setup) and 70 // then close them in TearDown before calling CocoaTest::TearDown. 71 virtual void TearDown(); 72 73 // Retuns a test window that can be used by views and other UI objects 74 // as part of their tests. Is created lazily, and will be closed correctly 75 // in CocoaTest::TearDown. Note that it is a CocoaTestHelperWindow which 76 // has special handling for being Key. 77 CocoaTestHelperWindow* test_window(); 78 79 private: 80 // Return a set of currently open windows. Avoiding NSArray so 81 // contents aren't retained, the pointer values can only be used for 82 // comparison purposes. Using std::set to make progress-checking 83 // convenient. 84 static std::set<NSWindow*> ApplicationWindows(); 85 86 // Return a set of windows which are in |ApplicationWindows()| but 87 // not |initial_windows_|. 88 std::set<NSWindow*> WindowsLeft(); 89 90 bool called_tear_down_; 91 base::mac::ScopedNSAutoreleasePool pool_; 92 93 // Windows which existed at the beginning of the test. 94 std::set<NSWindow*> initial_windows_; 95 96 // Strong. Lazily created. This isn't wrapped in a scoped_nsobject because 97 // we want to call [close] to destroy it rather than calling [release]. We 98 // want to verify that [close] is actually removing our window and that it's 99 // not hanging around because releaseWhenClosed was set to "no" on the window. 100 // It isn't wrapped in a different wrapper class to close it because we 101 // need to close it at a very specific time; just before we enter our clean 102 // up loop in TearDown. 103 CocoaTestHelperWindow* test_window_; 104 }; 105 106 // A macro defining a standard set of tests to run on a view. Since we can't 107 // inherit tests, this macro saves us a lot of duplicate code. Handles simply 108 // displaying the view to make sure it won't crash, as well as removing it 109 // from a window. All tests that work with NSView subclasses and/or 110 // NSViewController subclasses should use it. 111 #define TEST_VIEW(test_fixture, test_view) \ 112 TEST_F(test_fixture, test_fixture##_TestViewMacroAddRemove) { \ 113 scoped_nsobject<NSView> view([test_view retain]); \ 114 EXPECT_EQ([test_window() contentView], [view superview]); \ 115 [view removeFromSuperview]; \ 116 EXPECT_FALSE([view superview]); \ 117 } \ 118 TEST_F(test_fixture, test_fixture##_TestViewMacroDisplay) { \ 119 [test_view display]; \ 120 } 121 122 // A macro which determines the proper float epsilon for a CGFloat. 123 #if CGFLOAT_IS_DOUBLE 124 #define CGFLOAT_EPSILON DBL_EPSILON 125 #else 126 #define CGFLOAT_EPSILON FLT_EPSILON 127 #endif 128 129 // A macro which which determines if two CGFloats are equal taking a 130 // proper epsilon into consideration. 131 #define CGFLOAT_EQ(expected, actual) \ 132 (actual >= (expected - CGFLOAT_EPSILON) && \ 133 actual <= (expected + CGFLOAT_EPSILON)) 134 135 // A test support macro which ascertains if two CGFloats are equal. 136 #define EXPECT_CGFLOAT_EQ(expected, actual) \ 137 EXPECT_TRUE(CGFLOAT_EQ(expected, actual)) << \ 138 expected << " != " << actual 139 140 // A test support macro which compares two NSRects for equality taking 141 // the float epsilon into consideration. 142 #define EXPECT_NSRECT_EQ(expected, actual) \ 143 EXPECT_TRUE(CGFLOAT_EQ(expected.origin.x, actual.origin.x) && \ 144 CGFLOAT_EQ(expected.origin.y, actual.origin.y) && \ 145 CGFLOAT_EQ(expected.size.width, actual.size.width) && \ 146 CGFLOAT_EQ(expected.size.height, actual.size.height)) << \ 147 "Rects do not match: " << \ 148 [NSStringFromRect(expected) UTF8String] << \ 149 " != " << [NSStringFromRect(actual) UTF8String] 150 151 #endif // CHROME_BROWSER_UI_COCOA_COCOA_TEST_HELPER_H_ 152