summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/cocoa_test_helper.h
blob: f980790579585032ba587641094c49cf29b564f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_COCOA_COCOA_TEST_HELPER_H_
#define CHROME_BROWSER_COCOA_COCOA_TEST_HELPER_H_

#import <Cocoa/Cocoa.h>
#include <vector>

#include "base/debug_util.h"
#include "base/file_path.h"
#include "base/mac_util.h"
#include "base/path_service.h"
#import "base/scoped_nsautorelease_pool.h"
#import "base/scoped_nsobject.h"
#include "base/scoped_ptr.h"
#include "chrome/common/chrome_constants.h"
#include "testing/platform_test.h"

// Background windows normally will not display things such as focus
// rings.  This class allows -isKeyWindow to be manipulated to test
// such things.
@interface CocoaTestHelperWindow : NSWindow {
 @private
  BOOL pretendIsKeyWindow_;
}

// Init a borderless non-deferred window with a backing store.
- (id)initWithContentRect:(NSRect)contentRect;

// Init with a default frame.
- (id)init;

// Sets the responder passed in as first responder, and sets the window
// so that it will return "YES" if asked if it key window. It does not actually
// make the window key.
- (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder;

// Clears the first responder duty for the window and returns the window
// to being non-key.
- (void)clearPretendKeyWindowAndFirstResponder;

// Set value to return for -isKeyWindow.
- (void)setPretendIsKeyWindow:(BOOL)isKeyWindow;

- (BOOL)isKeyWindow;

@end

// A test class that all tests that depend on AppKit should inherit from.
// Sets up NSApplication and paths correctly, and makes sure that any windows
// created in the test are closed down properly by the test. If you need to
// inherit from a different test class, but need to set up the AppKit runtime
// environment, you can call BootstrapCocoa directly from your test class. You
// will have to deal with windows on your own though.
class CocoaTest : public PlatformTest {
 public:
  // Sets up AppKit and paths correctly for unit tests. If you can't inherit
  // from CocoaTest but are going to be using any AppKit features directly,
  // or indirectly, you should be calling this from the c'tor or SetUp methods
  // of your test class.
  static void BootstrapCocoa();

  CocoaTest();
  virtual ~CocoaTest();

  // Must be called by subclasses that override TearDown. We verify that it
  // is called in our destructor. Takes care of making sure that all windows
  // are closed off correctly. If your tests open windows, they must be sure
  // to close them before CocoaTest::TearDown is called. A standard way of doing
  // this would be to create them in SetUp (after calling CocoaTest::Setup) and
  // then close them in TearDown before calling CocoaTest::TearDown.
  virtual void TearDown();

  // Retuns a test window that can be used by views and other UI objects
  // as part of their tests. Is created lazily, and will be closed correctly
  // in CocoaTest::TearDown. Note that it is a CocoaTestHelperWindow which
  // has special handling for being Key.
  CocoaTestHelperWindow* test_window();

 private:
  // Return a vector of currently open windows. Note that it is a vector
  // instead of an NSArray because we don't want any retains placed on the
  // windows in it and that the windows in this list may no longer be valid
  // NSWindows any time after this returns. You can only use the pointer values
  // in the vector for comparison purposes.
  static std::vector<NSWindow*> ApplicationWindows();

  bool called_tear_down_;
  base::ScopedNSAutoreleasePool pool_;
  std::vector<NSWindow*> initial_windows_;
  // Strong. Lazily created. This isn't wrapped in a scoped_nsobject because
  // we want to call [close] to destroy it rather than calling [release]. We
  // want to verify that [close] is actually removing our window and that it's
  // not hanging around because releaseWhenClosed was set to "no" on the window.
  // It isn't wrapped in a different wrapper class to close it because we
  // need to close it at a very specific time; just before we enter our clean
  // up loop in TearDown.
  CocoaTestHelperWindow* test_window_;
};

// A macro defining a standard set of tests to run on a view. Since we can't
// inherit tests, this macro saves us a lot of duplicate code. Handles simply
// displaying the view to make sure it won't crash, as well as removing it
// from a window. All tests that work with NSView subclasses and/or
// NSViewController subclasses should use it.
#define TEST_VIEW(test_fixture, view_member_name) \
  TEST_F(test_fixture, AddRemove##test_fixture) { \
    scoped_nsobject<NSView> view([view_member_name retain]); \
    EXPECT_EQ([test_window() contentView], [view_member_name superview]); \
    [view_member_name removeFromSuperview]; \
    EXPECT_FALSE([view_member_name superview]); \
  } \
  TEST_F(test_fixture, Display##test_fixture) { \
    [view_member_name display]; \
  }

// The classes below are deprecated and will be removed shortly. Do not write
// any tests based on them.

// A class that initializes Cocoa and sets up resources for many of our
// Cocoa controller unit tests. It does several key things:
//   - Creates and displays an empty Cocoa window for views to live in
//   - Loads the appropriate bundle so nib loading works. When loading the
//     nib in the class being tested, your must use |mac_util::MainAppBundle()|
//     as the bundle. If you do not specify a bundle, your test will likely
//     fail.
// It currently does not create an autorelease pool, though that can easily be
// added. If your test wants one, it can derive from PlatformTest instead of
// testing::Test.

// Provides the Cocoa goodness without the extraneous window.

// DEPRECATED
// TODO(dmaclach): remove as soon as I can get my other CLs in that get rid
//                 of any dependencies on this. 10/30/09 at the latest.
class CocoaNoWindowTestHelper {
 public:
  CocoaNoWindowTestHelper() {
    // Look in the framework bundle for resources.
    FilePath path;
    PathService::Get(base::DIR_EXE, &path);
    path = path.Append(chrome::kFrameworkName);
    mac_util::SetOverrideAppBundlePath(path);

    // Bootstrap Cocoa. It's very unhappy without this.
    [NSApplication sharedApplication];

    // Set the duration of AppKit-evaluated animations (such as frame changes)
    // to zero for testing purposes. That way they take effect immediately.
    [[NSAnimationContext currentContext] setDuration:0.0];
  }
};

// DEPRECATED
// TODO(dmaclach): remove as soon as I can get my other CLs in that get rid
//                 of any dependencies on this. 10/30/09 at the latest.
class CocoaTestHelper : public CocoaNoWindowTestHelper {
 public:
  CocoaTestHelper() {
    window_.reset([[CocoaTestHelperWindow alloc] init]);
    if (DebugUtil::BeingDebugged()) {
      [window_ orderFront:nil];
    } else {
      [window_ orderBack:nil];
    }
  }

  // Access the Cocoa window created for the test.
  NSWindow* window() const { return window_.get(); }
  NSView* contentView() const { return [window_ contentView]; }

  // Set |window_| to pretend to be key and make |aView| its
  // firstResponder.
  void makeFirstResponder(NSView* aView) {
    [window_ makeFirstResponder:aView];
    [window_ setPretendIsKeyWindow:YES];
  }

  // Clear |window_| firstResponder and stop pretending to be key.
  void clearFirstResponder() {
    [window_ setPretendIsKeyWindow:NO];
    [window_ makeFirstResponder:nil];
  }

 private:
  scoped_nsobject<CocoaTestHelperWindow> window_;
};

#endif  // CHROME_BROWSER_COCOA_COCOA_TEST_HELPER_H_