OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 #import <Cocoa/Cocoa.h> | |
6 | |
7 #import "chrome/browser/ui/cocoa/reload_button.h" | |
8 | |
9 #include "base/scoped_nsobject.h" | |
10 #include "chrome/app/chrome_command_ids.h" | |
11 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" | |
12 #import "chrome/browser/ui/cocoa/test_event_utils.h" | |
13 #import "testing/gtest_mac.h" | |
14 #include "testing/platform_test.h" | |
15 #import "third_party/ocmock/OCMock/OCMock.h" | |
16 | |
17 @protocol TargetActionMock <NSObject> | |
18 - (void)anAction:(id)sender; | |
19 @end | |
20 | |
21 namespace { | |
22 | |
23 class ReloadButtonTest : public CocoaTest { | |
24 public: | |
25 ReloadButtonTest() { | |
26 NSRect frame = NSMakeRect(0, 0, 20, 20); | |
27 scoped_nsobject<ReloadButton> button( | |
28 [[ReloadButton alloc] initWithFrame:frame]); | |
29 button_ = button.get(); | |
30 | |
31 // Set things up so unit tests have a reliable baseline. | |
32 [button_ setTag:IDC_RELOAD]; | |
33 [button_ awakeFromNib]; | |
34 | |
35 [[test_window() contentView] addSubview:button_]; | |
36 } | |
37 | |
38 ReloadButton* button_; | |
39 }; | |
40 | |
41 TEST_VIEW(ReloadButtonTest, button_) | |
42 | |
43 // Test that mouse-tracking is setup and does the right thing. | |
44 TEST_F(ReloadButtonTest, IsMouseInside) { | |
45 EXPECT_TRUE([[button_ trackingAreas] containsObject:[button_ trackingArea]]); | |
46 | |
47 EXPECT_FALSE([button_ isMouseInside]); | |
48 [button_ mouseEntered:nil]; | |
49 EXPECT_TRUE([button_ isMouseInside]); | |
50 [button_ mouseExited:nil]; | |
51 } | |
52 | |
53 // Verify that multiple clicks do not result in multiple messages to | |
54 // the target. | |
55 TEST_F(ReloadButtonTest, IgnoredMultiClick) { | |
56 id mock_target = [OCMockObject mockForProtocol:@protocol(TargetActionMock)]; | |
57 [button_ setTarget:mock_target]; | |
58 [button_ setAction:@selector(anAction:)]; | |
59 | |
60 // Expect the action once. | |
61 [[mock_target expect] anAction:button_]; | |
62 | |
63 const std::pair<NSEvent*,NSEvent*> click_one = | |
64 test_event_utils::MouseClickInView(button_, 1); | |
65 const std::pair<NSEvent*,NSEvent*> click_two = | |
66 test_event_utils::MouseClickInView(button_, 2); | |
67 [NSApp postEvent:click_one.second atStart:YES]; | |
68 [button_ mouseDown:click_one.first]; | |
69 [NSApp postEvent:click_two.second atStart:YES]; | |
70 [button_ mouseDown:click_two.first]; | |
71 | |
72 [button_ setTarget:nil]; | |
73 } | |
74 | |
75 TEST_F(ReloadButtonTest, UpdateTag) { | |
76 [button_ setTag:IDC_STOP]; | |
77 | |
78 [button_ updateTag:IDC_RELOAD]; | |
79 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
80 NSImage* reloadImage = [button_ image]; | |
81 NSString* const reloadToolTip = [button_ toolTip]; | |
82 | |
83 [button_ updateTag:IDC_STOP]; | |
84 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
85 NSImage* stopImage = [button_ image]; | |
86 NSString* const stopToolTip = [button_ toolTip]; | |
87 EXPECT_NSNE(reloadImage, stopImage); | |
88 EXPECT_NSNE(reloadToolTip, stopToolTip); | |
89 | |
90 [button_ updateTag:IDC_RELOAD]; | |
91 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
92 EXPECT_NSEQ(reloadImage, [button_ image]); | |
93 EXPECT_NSEQ(reloadToolTip, [button_ toolTip]); | |
94 } | |
95 | |
96 // Test that when forcing the mode, it takes effect immediately, | |
97 // regardless of whether the mouse is hovering. | |
98 TEST_F(ReloadButtonTest, SetIsLoadingForce) { | |
99 EXPECT_FALSE([button_ isMouseInside]); | |
100 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
101 | |
102 // Changes to stop immediately. | |
103 [button_ setIsLoading:YES force:YES]; | |
104 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
105 | |
106 // Changes to reload immediately. | |
107 [button_ setIsLoading:NO force:YES]; | |
108 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
109 | |
110 // Changes to stop immediately when the mouse is hovered, and | |
111 // doesn't change when the mouse exits. | |
112 [button_ mouseEntered:nil]; | |
113 EXPECT_TRUE([button_ isMouseInside]); | |
114 [button_ setIsLoading:YES force:YES]; | |
115 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
116 [button_ mouseExited:nil]; | |
117 EXPECT_FALSE([button_ isMouseInside]); | |
118 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
119 | |
120 // Changes to reload immediately when the mouse is hovered, and | |
121 // doesn't change when the mouse exits. | |
122 [button_ mouseEntered:nil]; | |
123 EXPECT_TRUE([button_ isMouseInside]); | |
124 [button_ setIsLoading:NO force:YES]; | |
125 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
126 [button_ mouseExited:nil]; | |
127 EXPECT_FALSE([button_ isMouseInside]); | |
128 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
129 } | |
130 | |
131 // Test that without force, stop mode is set immediately, but reload | |
132 // is affected by the hover status. | |
133 TEST_F(ReloadButtonTest, SetIsLoadingNoForceUnHover) { | |
134 EXPECT_FALSE([button_ isMouseInside]); | |
135 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
136 | |
137 // Changes to stop immediately when the mouse is not hovering. | |
138 [button_ setIsLoading:YES force:NO]; | |
139 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
140 | |
141 // Changes to reload immediately when the mouse is not hovering. | |
142 [button_ setIsLoading:NO force:NO]; | |
143 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
144 | |
145 // Changes to stop immediately when the mouse is hovered, and | |
146 // doesn't change when the mouse exits. | |
147 [button_ mouseEntered:nil]; | |
148 EXPECT_TRUE([button_ isMouseInside]); | |
149 [button_ setIsLoading:YES force:NO]; | |
150 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
151 [button_ mouseExited:nil]; | |
152 EXPECT_FALSE([button_ isMouseInside]); | |
153 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
154 | |
155 // Does not change to reload immediately when the mouse is hovered, | |
156 // changes when the mouse exits. | |
157 [button_ mouseEntered:nil]; | |
158 EXPECT_TRUE([button_ isMouseInside]); | |
159 [button_ setIsLoading:NO force:NO]; | |
160 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
161 [button_ mouseExited:nil]; | |
162 EXPECT_FALSE([button_ isMouseInside]); | |
163 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
164 } | |
165 | |
166 // Test that without force, stop mode is set immediately, and reload | |
167 // will be set after a timeout. | |
168 // TODO(shess): Reenable, http://crbug.com/61485 | |
169 TEST_F(ReloadButtonTest, DISABLED_SetIsLoadingNoForceTimeout) { | |
170 // When the event loop first spins, some delayed tracking-area setup | |
171 // is done, which causes -mouseExited: to be called. Spin it at | |
172 // least once, and dequeue any pending events. | |
173 // TODO(shess): It would be more reasonable to have an MockNSTimer | |
174 // factory for the class to use, which this code could fire | |
175 // directly. | |
176 while ([NSApp nextEventMatchingMask:NSAnyEventMask | |
177 untilDate:nil | |
178 inMode:NSDefaultRunLoopMode | |
179 dequeue:YES]) { | |
180 } | |
181 | |
182 const NSTimeInterval kShortTimeout = 0.1; | |
183 [ReloadButton setPendingReloadTimeout:kShortTimeout]; | |
184 | |
185 EXPECT_FALSE([button_ isMouseInside]); | |
186 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
187 | |
188 // Move the mouse into the button and press it. | |
189 [button_ mouseEntered:nil]; | |
190 EXPECT_TRUE([button_ isMouseInside]); | |
191 [button_ setIsLoading:YES force:NO]; | |
192 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
193 | |
194 // Does not change to reload immediately when the mouse is hovered. | |
195 EXPECT_TRUE([button_ isMouseInside]); | |
196 [button_ setIsLoading:NO force:NO]; | |
197 EXPECT_TRUE([button_ isMouseInside]); | |
198 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
199 EXPECT_TRUE([button_ isMouseInside]); | |
200 | |
201 // Spin event loop until the timeout passes. | |
202 NSDate* pastTimeout = [NSDate dateWithTimeIntervalSinceNow:2 * kShortTimeout]; | |
203 [NSApp nextEventMatchingMask:NSAnyEventMask | |
204 untilDate:pastTimeout | |
205 inMode:NSDefaultRunLoopMode | |
206 dequeue:NO]; | |
207 | |
208 // Mouse is still hovered, button is in reload mode. If the mouse | |
209 // is no longer hovered, see comment at top of function. | |
210 EXPECT_TRUE([button_ isMouseInside]); | |
211 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
212 } | |
213 | |
214 // Test that pressing stop after reload mode has been requested | |
215 // doesn't forward the stop message. | |
216 TEST_F(ReloadButtonTest, StopAfterReloadSet) { | |
217 id mock_target = [OCMockObject mockForProtocol:@protocol(TargetActionMock)]; | |
218 [button_ setTarget:mock_target]; | |
219 [button_ setAction:@selector(anAction:)]; | |
220 | |
221 EXPECT_FALSE([button_ isMouseInside]); | |
222 | |
223 // Get to stop mode. | |
224 [button_ setIsLoading:YES force:YES]; | |
225 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
226 EXPECT_TRUE([button_ isEnabled]); | |
227 | |
228 // Expect the action once. | |
229 [[mock_target expect] anAction:button_]; | |
230 | |
231 // Clicking in stop mode should send the action and transition to | |
232 // reload mode. | |
233 const std::pair<NSEvent*,NSEvent*> click = | |
234 test_event_utils::MouseClickInView(button_, 1); | |
235 [NSApp postEvent:click.second atStart:YES]; | |
236 [button_ mouseDown:click.first]; | |
237 EXPECT_EQ(IDC_RELOAD, [button_ tag]); | |
238 EXPECT_TRUE([button_ isEnabled]); | |
239 | |
240 // Get back to stop mode. | |
241 [button_ setIsLoading:YES force:YES]; | |
242 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
243 EXPECT_TRUE([button_ isEnabled]); | |
244 | |
245 // If hover prevented reload mode immediately taking effect, clicks should do | |
246 // nothing, because the button should be disabled. | |
247 [button_ mouseEntered:nil]; | |
248 EXPECT_TRUE([button_ isMouseInside]); | |
249 [button_ setIsLoading:NO force:NO]; | |
250 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
251 EXPECT_FALSE([button_ isEnabled]); | |
252 [NSApp postEvent:click.second atStart:YES]; | |
253 [button_ mouseDown:click.first]; | |
254 EXPECT_EQ(IDC_STOP, [button_ tag]); | |
255 | |
256 [button_ setTarget:nil]; | |
257 } | |
258 | |
259 } // namespace | |
OLD | NEW |