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