fullscreen_controller_state_test.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1// Copyright (c) 2012 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#include "chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h" 6 7#include <memory.h> 8 9#include <iomanip> 10#include <iostream> 11 12#include "chrome/browser/fullscreen.h" 13#include "chrome/browser/ui/browser.h" 14#include "chrome/browser/ui/browser_window.h" 15#include "chrome/browser/ui/fullscreen/fullscreen_controller.h" 16#include "chrome/browser/ui/fullscreen/fullscreen_controller_test.h" 17#include "chrome/browser/ui/tabs/tab_strip_model.h" 18#include "content/public/common/url_constants.h" 19#include "testing/gtest/include/gtest/gtest.h" 20 21#if defined(OS_MACOSX) 22#include "base/mac/mac_util.h" 23#endif 24 25namespace { 26 27bool SupportsMacSystemFullscreen() { 28#if defined(OS_MACOSX) 29 return chrome::mac::SupportsSystemFullscreen(); 30#else 31 return false; 32#endif 33} 34 35} // namespace 36 37FullscreenControllerStateTest::FullscreenControllerStateTest() 38 : state_(STATE_NORMAL), 39 last_notification_received_state_(STATE_NORMAL) { 40 // Human specified state machine data. 41 // For each state, for each event, define the resulting state. 42 State transition_table_data[][NUM_EVENTS] = { 43 { // STATE_NORMAL: 44 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN 45 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME 46 STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE 47 STATE_NORMAL, // Event TAB_FULLSCREEN_FALSE 48 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE 49 STATE_NORMAL, // Event METRO_SNAP_FALSE 50 STATE_NORMAL, // Event BUBBLE_EXIT_LINK 51 STATE_NORMAL, // Event BUBBLE_ALLOW 52 STATE_NORMAL, // Event BUBBLE_DENY 53 STATE_NORMAL, // Event WINDOW_CHANGE 54 }, 55 { // STATE_BROWSER_FULLSCREEN_NO_CHROME: 56 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN 57 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TOGGLE_FULLSCREEN_CHROME 58 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE 59 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE 60 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE 61 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE 62 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK 63 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_ALLOW 64 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY 65 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE 66 }, 67 { // STATE_BROWSER_FULLSCREEN_WITH_CHROME: 68 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN 69 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME 70 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event TAB_FULLSCREEN_TRUE 71 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TAB_FULLSCREEN_FALSE 72 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event METRO_SNAP_TRUE 73 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event METRO_SNAP_FALSE 74 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK 75 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_ALLOW 76 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_DENY 77 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event WINDOW_CHANGE 78 }, 79 { // STATE_METRO_SNAP: 80 STATE_METRO_SNAP, // Event TOGGLE_FULLSCREEN 81 STATE_METRO_SNAP, // Event TOGGLE_FULLSCREEN_CHROME 82 STATE_METRO_SNAP, // Event TAB_FULLSCREEN_TRUE 83 STATE_METRO_SNAP, // Event TAB_FULLSCREEN_FALSE 84 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE 85 STATE_NORMAL, // Event METRO_SNAP_FALSE 86 STATE_METRO_SNAP, // Event BUBBLE_EXIT_LINK 87 STATE_METRO_SNAP, // Event BUBBLE_ALLOW 88 STATE_METRO_SNAP, // Event BUBBLE_DENY 89 STATE_METRO_SNAP, // Event WINDOW_CHANGE 90 }, 91 { // STATE_TAB_FULLSCREEN: 92 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN 93 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME 94 STATE_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE 95 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE 96 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE 97 STATE_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE 98 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK 99 STATE_TAB_FULLSCREEN, // Event BUBBLE_ALLOW 100 STATE_TO_NORMAL, // Event BUBBLE_DENY 101 STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE 102 }, 103 { // STATE_TAB_BROWSER_FULLSCREEN: 104 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN 105 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME 106 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE 107 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE 108 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE 109 STATE_TAB_BROWSER_FULLSCREEN, // Event METRO_SNAP_FALSE 110 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_EXIT_LINK 111 STATE_TAB_BROWSER_FULLSCREEN, // Event BUBBLE_ALLOW 112 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY 113 STATE_TAB_BROWSER_FULLSCREEN, // Event WINDOW_CHANGE 114 }, 115 { // STATE_TAB_BROWSER_FULLSCREEN_CHROME: 116 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN 117 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME 118 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event TAB_FULLSCREEN_TRUE 119 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event TAB_FULLSCREEN_FALSE 120 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE 121 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event METRO_SNAP_FALSE 122 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_EXIT_LINK 123 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event BUBBLE_ALLOW 124 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event BUBBLE_DENY 125 STATE_TAB_BROWSER_FULLSCREEN_CHROME, // Event WINDOW_CHANGE 126 }, 127 { // STATE_TO_NORMAL: 128 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN 129 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME 130 // TODO(scheib) Should be a route back to TAB. http://crbug.com/154196 131 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_TRUE 132 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE 133 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE 134 STATE_TO_NORMAL, // Event METRO_SNAP_FALSE 135 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK 136 STATE_TO_NORMAL, // Event BUBBLE_ALLOW 137 STATE_TO_NORMAL, // Event BUBBLE_DENY 138 STATE_NORMAL, // Event WINDOW_CHANGE 139 }, 140 { // STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: 141 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN 142 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TOGGLE_FULLSCREEN_CHROME 143 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196 144 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_TRUE 145 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE 146 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE 147 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event METRO_SNAP_FALSE 148#if defined(OS_MACOSX) 149 // Mac window reports fullscreen immediately and an exit triggers exit. 150 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK 151#else 152 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_EXIT_LINK 153#endif 154 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_ALLOW 155 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event BUBBLE_DENY 156 STATE_BROWSER_FULLSCREEN_NO_CHROME, // Event WINDOW_CHANGE 157 }, 158 { // STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME: 159 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TOGGLE_FULLSCREEN 160 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME 161 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196 162 STATE_TAB_BROWSER_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE 163 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event TAB_FULLSCREEN_FALSE 164 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event METRO_SNAP_TRUE 165 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event METRO_SNAP_FALSE 166 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK 167 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event BUBBLE_ALLOW 168 STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,// Event BUBBLE_DENY 169 STATE_BROWSER_FULLSCREEN_WITH_CHROME, // Event WINDOW_CHANGE 170 }, 171 { // STATE_TO_TAB_FULLSCREEN: 172 // TODO(scheib) Should be a route to TAB_BROWSER http://crbug.com/154196 173 STATE_TO_TAB_FULLSCREEN, // Event TOGGLE_FULLSCREEN 174 STATE_TO_NORMAL, // Event TOGGLE_FULLSCREEN_CHROME 175 STATE_TO_TAB_FULLSCREEN, // Event TAB_FULLSCREEN_TRUE 176#if defined(OS_MACOSX) 177 // Mac runs as expected due to a forced NotifyTabOfExitIfNecessary(); 178 STATE_TO_NORMAL, // Event TAB_FULLSCREEN_FALSE 179#else 180 // TODO(scheib) Should be a route back to NORMAL. http://crbug.com/154196 181 STATE_TO_BROWSER_FULLSCREEN_NO_CHROME, // Event TAB_FULLSCREEN_FALSE 182#endif 183 STATE_METRO_SNAP, // Event METRO_SNAP_TRUE 184 STATE_TO_TAB_FULLSCREEN, // Event METRO_SNAP_FALSE 185#if defined(OS_MACOSX) 186 // Mac window reports fullscreen immediately and an exit triggers exit. 187 STATE_TO_NORMAL, // Event BUBBLE_EXIT_LINK 188#else 189 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_EXIT_LINK 190#endif 191 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_ALLOW 192#if defined(OS_MACOSX) 193 // Mac window reports fullscreen immediately and an exit triggers exit. 194 STATE_TO_NORMAL, // Event BUBBLE_DENY 195#else 196 STATE_TO_TAB_FULLSCREEN, // Event BUBBLE_DENY 197#endif 198 STATE_TAB_FULLSCREEN, // Event WINDOW_CHANGE 199 }, 200 }; 201 CHECK_EQ(sizeof(transition_table_data), sizeof(transition_table_)); 202 memcpy(transition_table_, transition_table_data, 203 sizeof(transition_table_data)); 204 205 // Verify that transition_table_ has been completely defined. 206 for (int source = 0; source < NUM_STATES; source++) { 207 for (int event = 0; event < NUM_EVENTS; event++) { 208 CHECK_NE(STATE_INVALID, transition_table_[source][event]); 209 CHECK_LE(0, transition_table_[source][event]); 210 CHECK_GT(NUM_STATES, transition_table_[source][event]); 211 } 212 } 213 214 // Copy transition_table_ data into state_transitions_ table. 215 for (int source = 0; source < NUM_STATES; source++) { 216 for (int event = 0; event < NUM_EVENTS; event++) { 217 if (ShouldSkipStateAndEventPair(static_cast<State>(source), 218 static_cast<Event>(event))) 219 continue; 220 State destination = transition_table_[source][event]; 221 state_transitions_[source][destination].event = static_cast<Event>(event); 222 state_transitions_[source][destination].state = destination; 223 state_transitions_[source][destination].distance = 1; 224 } 225 } 226} 227 228FullscreenControllerStateTest::~FullscreenControllerStateTest() { 229} 230 231// static 232const char* FullscreenControllerStateTest::GetStateString(State state) { 233 switch (state) { 234 case STATE_NORMAL: 235 return "STATE_NORMAL"; 236 case STATE_BROWSER_FULLSCREEN_NO_CHROME: 237 return "STATE_BROWSER_FULLSCREEN_NO_CHROME"; 238 case STATE_BROWSER_FULLSCREEN_WITH_CHROME: 239 return "STATE_BROWSER_FULLSCREEN_WITH_CHROME"; 240 case STATE_METRO_SNAP: 241 return "STATE_METRO_SNAP"; 242 case STATE_TAB_FULLSCREEN: 243 return "STATE_TAB_FULLSCREEN"; 244 case STATE_TAB_BROWSER_FULLSCREEN: 245 return "STATE_TAB_BROWSER_FULLSCREEN"; 246 case STATE_TAB_BROWSER_FULLSCREEN_CHROME: 247 return "STATE_TAB_BROWSER_FULLSCREEN_CHROME"; 248 case STATE_TO_NORMAL: 249 return "STATE_TO_NORMAL"; 250 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: 251 return "STATE_TO_BROWSER_FULLSCREEN_NO_CHROME"; 252 case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME: 253 return "STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME"; 254 case STATE_TO_TAB_FULLSCREEN: 255 return "STATE_TO_TAB_FULLSCREEN"; 256 case STATE_INVALID: 257 return "STATE_INVALID"; 258 default: 259 NOTREACHED() << "No string for state " << state; 260 return "State-Unknown"; 261 } 262} 263 264// static 265const char* FullscreenControllerStateTest::GetEventString(Event event) { 266 switch (event) { 267 case TOGGLE_FULLSCREEN: 268 return "TOGGLE_FULLSCREEN"; 269 case TOGGLE_FULLSCREEN_CHROME: 270 return "TOGGLE_FULLSCREEN_CHROME"; 271 case TAB_FULLSCREEN_TRUE: 272 return "TAB_FULLSCREEN_TRUE"; 273 case TAB_FULLSCREEN_FALSE: 274 return "TAB_FULLSCREEN_FALSE"; 275 case METRO_SNAP_TRUE: 276 return "METRO_SNAP_TRUE"; 277 case METRO_SNAP_FALSE: 278 return "METRO_SNAP_FALSE"; 279 case BUBBLE_EXIT_LINK: 280 return "BUBBLE_EXIT_LINK"; 281 case BUBBLE_ALLOW: 282 return "BUBBLE_ALLOW"; 283 case BUBBLE_DENY: 284 return "BUBBLE_DENY"; 285 case WINDOW_CHANGE: 286 return "WINDOW_CHANGE"; 287 case EVENT_INVALID: 288 return "EVENT_INVALID"; 289 default: 290 NOTREACHED() << "No string for event " << event; 291 return "Event-Unknown"; 292 } 293} 294 295// static 296bool FullscreenControllerStateTest::IsReentrant() { 297#if defined(TOOLKIT_VIEWS) 298 return true; 299#else 300 return false; 301#endif 302} 303 304// static 305bool FullscreenControllerStateTest::IsPersistentState(State state) { 306 switch (state) { 307 case STATE_NORMAL: 308 case STATE_BROWSER_FULLSCREEN_NO_CHROME: 309 case STATE_BROWSER_FULLSCREEN_WITH_CHROME: 310 case STATE_METRO_SNAP: 311 case STATE_TAB_FULLSCREEN: 312 case STATE_TAB_BROWSER_FULLSCREEN: 313 case STATE_TAB_BROWSER_FULLSCREEN_CHROME: 314 return true; 315 case STATE_TO_NORMAL: 316 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: 317 case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME: 318 case STATE_TO_TAB_FULLSCREEN: 319 return false; 320 default: 321 NOTREACHED(); 322 return false; 323 } 324} 325 326void FullscreenControllerStateTest::TransitionToState(State final_state) { 327 int max_steps = NUM_STATES; 328 while (max_steps-- && TransitionAStepTowardState(final_state)) 329 continue; 330 ASSERT_GE(max_steps, 0) << "TransitionToState was unable to achieve desired " 331 << "target state. TransitionAStepTowardState iterated too many times." 332 << GetAndClearDebugLog(); 333 ASSERT_EQ(final_state, state_) << "TransitionToState was unable to achieve " 334 << "desired target state. TransitionAStepTowardState returned false." 335 << GetAndClearDebugLog(); 336} 337 338bool FullscreenControllerStateTest::TransitionAStepTowardState( 339 State destination_state) { 340 State source_state = state_; 341 if (source_state == destination_state) 342 return false; 343 344 StateTransitionInfo next = NextTransitionInShortestPath(source_state, 345 destination_state, 346 NUM_STATES); 347 if (next.state == STATE_INVALID) { 348 NOTREACHED() << "TransitionAStepTowardState unable to transition. " 349 << "NextTransitionInShortestPath(" 350 << GetStateString(source_state) << ", " 351 << GetStateString(destination_state) << ") returned STATE_INVALID." 352 << GetAndClearDebugLog(); 353 return false; 354 } 355 356 return InvokeEvent(next.event); 357} 358 359const char* FullscreenControllerStateTest::GetWindowStateString() { 360 return NULL; 361} 362 363bool FullscreenControllerStateTest::InvokeEvent(Event event) { 364 if (!fullscreen_notification_observer_.get()) { 365 // Start observing NOTIFICATION_FULLSCREEN_CHANGED. Construct the 366 // notification observer here instead of in 367 // FullscreenControllerStateTest::FullscreenControllerStateTest() so that we 368 // listen to notifications on the proper thread. 369 fullscreen_notification_observer_.reset( 370 new FullscreenNotificationObserver()); 371 } 372 373 State source_state = state_; 374 State next_state = transition_table_[source_state][event]; 375 376 EXPECT_FALSE(ShouldSkipStateAndEventPair(source_state, event)) 377 << GetAndClearDebugLog(); 378 379 // When simulating reentrant window change calls, expect the next state 380 // automatically. 381 if (IsReentrant()) 382 next_state = transition_table_[next_state][WINDOW_CHANGE]; 383 384 debugging_log_ << " InvokeEvent(" << std::left 385 << std::setw(MAX_EVENT_NAME_LENGTH) << GetEventString(event) 386 << ") to " 387 << std::setw(MAX_STATE_NAME_LENGTH) << GetStateString(next_state); 388 389 state_ = next_state; 390 391 switch (event) { 392 case TOGGLE_FULLSCREEN: 393 GetFullscreenController()->ToggleFullscreenMode(); 394 break; 395 case TOGGLE_FULLSCREEN_CHROME: 396#if defined(OS_MACOSX) 397 if (chrome::mac::SupportsSystemFullscreen()) { 398 GetFullscreenController()->ToggleFullscreenWithChrome(); 399 break; 400 } 401#endif 402 NOTREACHED() << GetAndClearDebugLog(); 403 break; 404 case TAB_FULLSCREEN_TRUE: 405 GetFullscreenController()->ToggleFullscreenModeForTab( 406 GetBrowser()->tab_strip_model()->GetActiveWebContents(), true); 407 break; 408 case TAB_FULLSCREEN_FALSE: 409 GetFullscreenController()->ToggleFullscreenModeForTab( 410 GetBrowser()->tab_strip_model()->GetActiveWebContents(), false); 411 break; 412 case METRO_SNAP_TRUE: 413#if defined(OS_WIN) 414 GetFullscreenController()->SetMetroSnapMode(true); 415#else 416 NOTREACHED() << GetAndClearDebugLog(); 417#endif 418 break; 419 case METRO_SNAP_FALSE: 420#if defined(OS_WIN) 421 GetFullscreenController()->SetMetroSnapMode(false); 422#else 423 NOTREACHED() << GetAndClearDebugLog(); 424#endif 425 break; 426 case BUBBLE_EXIT_LINK: 427 GetFullscreenController()->ExitTabOrBrowserFullscreenToPreviousState(); 428 break; 429 case BUBBLE_ALLOW: 430 GetFullscreenController()->OnAcceptFullscreenPermission(); 431 break; 432 case BUBBLE_DENY: 433 GetFullscreenController()->OnDenyFullscreenPermission(); 434 break; 435 case WINDOW_CHANGE: 436 ChangeWindowFullscreenState(); 437 break; 438 default: 439 NOTREACHED() << "InvokeEvent needs a handler for event " 440 << GetEventString(event) << GetAndClearDebugLog(); 441 return false; 442 } 443 444 if (GetWindowStateString()) 445 debugging_log_ << " Window state now " << GetWindowStateString() << "\n"; 446 else 447 debugging_log_ << "\n"; 448 449 MaybeWaitForNotification(); 450 VerifyWindowState(); 451 452 return true; 453} 454 455void FullscreenControllerStateTest::VerifyWindowState() { 456 switch (state_) { 457 case STATE_NORMAL: 458#if defined(OS_MACOSX) 459 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithChrome()) 460 << GetAndClearDebugLog(); 461 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithoutChrome()) 462 << GetAndClearDebugLog(); 463#endif 464 EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser()) 465 << GetAndClearDebugLog(); 466 EXPECT_FALSE(GetFullscreenController()->IsFullscreenForTabOrPending()) 467 << GetAndClearDebugLog(); 468 EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) 469 << GetAndClearDebugLog(); 470 break; 471 case STATE_BROWSER_FULLSCREEN_NO_CHROME: 472#if defined(OS_MACOSX) 473 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithChrome()) 474 << GetAndClearDebugLog(); 475 EXPECT_TRUE(GetBrowser()->window()->IsFullscreenWithoutChrome()) 476 << GetAndClearDebugLog(); 477#endif 478 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser()) 479 << GetAndClearDebugLog(); 480 EXPECT_FALSE(GetFullscreenController()->IsFullscreenForTabOrPending()) 481 << GetAndClearDebugLog(); 482 EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) 483 << GetAndClearDebugLog(); 484 break; 485 case STATE_BROWSER_FULLSCREEN_WITH_CHROME: 486#if defined(OS_MACOSX) 487 EXPECT_TRUE(GetBrowser()->window()->IsFullscreenWithChrome()) 488 << GetAndClearDebugLog(); 489 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithoutChrome()) 490 << GetAndClearDebugLog(); 491#endif 492 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser()) 493 << GetAndClearDebugLog(); 494 EXPECT_FALSE(GetFullscreenController()->IsFullscreenForTabOrPending()) 495 << GetAndClearDebugLog(); 496 EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) 497 << GetAndClearDebugLog(); 498 break; 499 case STATE_METRO_SNAP: 500#if defined(OS_WIN) 501 // http://crbug.com/169138 502 // No expectation for IsFullscreenWithChrome() or 503 // IsFullscreenWithoutChrome() 504 505 // TODO(scheib) IsFullscreenForBrowser and IsFullscreenForTabOrPending 506 // are returning true and false in interactive tests with real window. 507 // With only a single Metro Snap state in this test framework it isn't 508 // fair to try to have an expectation anyway. 509 // 510 // No expectation for IsFullscreenForBrowser. 511 // No expectation for IsFullscreenForTabOrPending. 512 EXPECT_TRUE(GetFullscreenController()->IsInMetroSnapMode()) 513 << GetAndClearDebugLog(); 514#else 515 NOTREACHED() << GetAndClearDebugLog(); 516#endif 517 break; 518 case STATE_TAB_FULLSCREEN: 519#if defined(OS_MACOSX) 520 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithChrome()) 521 << GetAndClearDebugLog(); 522 EXPECT_TRUE(GetBrowser()->window()->IsFullscreenWithoutChrome()) 523 << GetAndClearDebugLog(); 524#endif 525 EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser()) 526 << GetAndClearDebugLog(); 527 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForTabOrPending()) 528 << GetAndClearDebugLog(); 529 EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) 530 << GetAndClearDebugLog(); 531 break; 532 case STATE_TAB_BROWSER_FULLSCREEN: 533#if defined(OS_MACOSX) 534 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithChrome()) 535 << GetAndClearDebugLog(); 536 EXPECT_TRUE(GetBrowser()->window()->IsFullscreenWithoutChrome()) 537 << GetAndClearDebugLog(); 538#endif 539 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser()) 540 << GetAndClearDebugLog(); 541 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForTabOrPending()) 542 << GetAndClearDebugLog(); 543 EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) 544 << GetAndClearDebugLog(); 545 break; 546 case STATE_TAB_BROWSER_FULLSCREEN_CHROME: 547#if defined(OS_MACOSX) 548 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithChrome()) 549 << GetAndClearDebugLog(); 550 EXPECT_TRUE(GetBrowser()->window()->IsFullscreenWithoutChrome()) 551 << GetAndClearDebugLog(); 552#endif 553 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser()) 554 << GetAndClearDebugLog(); 555 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForTabOrPending()) 556 << GetAndClearDebugLog(); 557 EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) 558 << GetAndClearDebugLog(); 559 break; 560 case STATE_TO_NORMAL: 561#if defined(OS_MACOSX) 562 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithChrome()) 563 << GetAndClearDebugLog(); 564 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithoutChrome()) 565 << GetAndClearDebugLog(); 566#endif 567 // No expectation for IsFullscreenForBrowser. 568 // No expectation for IsFullscreenForTabOrPending. 569 EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) 570 << GetAndClearDebugLog(); 571 break; 572 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME: 573#if defined(OS_MACOSX) 574 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithChrome()) 575 << GetAndClearDebugLog(); 576 EXPECT_TRUE(GetBrowser()->window()->IsFullscreenWithoutChrome()) 577 << GetAndClearDebugLog(); 578 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser()) 579 << GetAndClearDebugLog(); 580#else 581 EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser()) 582 << GetAndClearDebugLog(); 583#endif 584 // No expectation for IsFullscreenForTabOrPending. 585 EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) 586 << GetAndClearDebugLog(); 587 break; 588 case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME: 589#if defined(OS_MACOSX) 590 EXPECT_TRUE(GetBrowser()->window()->IsFullscreenWithChrome()) 591 << GetAndClearDebugLog(); 592 EXPECT_FALSE(GetBrowser()->window()->IsFullscreenWithoutChrome()) 593 << GetAndClearDebugLog(); 594 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser()) 595 << GetAndClearDebugLog(); 596#else 597 EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser()) 598 << GetAndClearDebugLog(); 599#endif 600 // No expectation for IsFullscreenForTabOrPending. 601 EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) 602 << GetAndClearDebugLog(); 603 break; 604 case STATE_TO_TAB_FULLSCREEN: 605#if defined(OS_MACOSX) 606 // TODO(scheib) InPresentationMode returns false when invoking events: 607 // TAB_FULLSCREEN_TRUE, TOGGLE_FULLSCREEN. http://crbug.com/156645 608 // It may be that a new testing state TO_TAB_BROWSER_FULLSCREEN 609 // would help work around this http://crbug.com/154196 610 // Test with: STATE_TO_TAB_FULLSCREEN__TOGGLE_FULLSCREEN 611 // 612 // EXPECT_TRUE(GetBrowser()->window()->InPresentationMode()) 613 // << GetAndClearDebugLog(); 614#endif 615 EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser()) 616 << GetAndClearDebugLog(); 617 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForTabOrPending()) 618 << GetAndClearDebugLog(); 619 EXPECT_FALSE(GetFullscreenController()->IsInMetroSnapMode()) 620 << GetAndClearDebugLog(); 621 break; 622 default: 623 NOTREACHED() << GetAndClearDebugLog(); 624 } 625} 626 627void FullscreenControllerStateTest::MaybeWaitForNotification() { 628 // We should get a fullscreen notification each time we get to a new 629 // persistent state. If we don't get a notification, the test will 630 // fail by timing out. 631 if (state_ != last_notification_received_state_ && 632 IsPersistentState(state_)) { 633 fullscreen_notification_observer_->Wait(); 634 last_notification_received_state_ = state_; 635 fullscreen_notification_observer_.reset( 636 new FullscreenNotificationObserver()); 637 } 638} 639 640void FullscreenControllerStateTest::TestTransitionsForEachState() { 641 for (int source_int = 0; source_int < NUM_STATES; source_int++) { 642 for (int event1_int = 0; event1_int < NUM_EVENTS; event1_int++) { 643 State state = static_cast<State>(source_int); 644 Event event1 = static_cast<Event>(event1_int); 645 646 // Early out if skipping all tests for this state, reduces log noise. 647 if (ShouldSkipTest(state, event1)) 648 continue; 649 650 for (int event2_int = 0; event2_int < NUM_EVENTS; event2_int++) { 651 for (int event3_int = 0; event3_int < NUM_EVENTS; event3_int++) { 652 Event event2 = static_cast<Event>(event2_int); 653 Event event3 = static_cast<Event>(event3_int); 654 655 // Test each state and each event. 656 ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, event1)) 657 << GetAndClearDebugLog(); 658 659 // Then, add an additional event to the sequence. 660 if (ShouldSkipStateAndEventPair(state_, event2)) 661 continue; 662 ASSERT_TRUE(InvokeEvent(event2)) << GetAndClearDebugLog(); 663 664 // Then, add an additional event to the sequence. 665 if (ShouldSkipStateAndEventPair(state_, event3)) 666 continue; 667 ASSERT_TRUE(InvokeEvent(event3)) << GetAndClearDebugLog(); 668 } 669 } 670 } 671 } 672} 673 674FullscreenControllerStateTest::StateTransitionInfo 675 FullscreenControllerStateTest::NextTransitionInShortestPath( 676 State source, State destination, int search_limit) { 677 if (search_limit == 0) 678 return StateTransitionInfo(); // Return a default (invalid) state. 679 680 if (state_transitions_[source][destination].state == STATE_INVALID) { 681 // Don't know the next state yet, do a depth first search. 682 StateTransitionInfo result; 683 684 // Consider all states reachable via each event from the source state. 685 for (int event_int = 0; event_int < NUM_EVENTS; event_int++) { 686 Event event = static_cast<Event>(event_int); 687 State next_state_candidate = transition_table_[source][event]; 688 689 if (ShouldSkipStateAndEventPair(source, event)) 690 continue; 691 692 // Recurse. 693 StateTransitionInfo candidate = NextTransitionInShortestPath( 694 next_state_candidate, destination, search_limit - 1); 695 696 if (candidate.distance + 1 < result.distance) { 697 result.event = event; 698 result.state = next_state_candidate; 699 result.distance = candidate.distance + 1; 700 } 701 } 702 703 // Cache result so that a search is not required next time. 704 state_transitions_[source][destination] = result; 705 } 706 707 return state_transitions_[source][destination]; 708} 709 710std::string FullscreenControllerStateTest::GetAndClearDebugLog() { 711 debugging_log_ << "(End of Debugging Log)\n"; 712 std::string output_log = "\nDebugging Log:\n" + debugging_log_.str(); 713 debugging_log_.str(std::string()); 714 return output_log; 715} 716 717bool FullscreenControllerStateTest::ShouldSkipStateAndEventPair(State state, 718 Event event) { 719 // TODO(scheib) Toggling Tab fullscreen while pending Tab or 720 // Browser fullscreen is broken currently http://crbug.com/154196 721 if ((state == STATE_TO_BROWSER_FULLSCREEN_NO_CHROME || 722 state == STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME || 723 state == STATE_TO_TAB_FULLSCREEN) && 724 (event == TAB_FULLSCREEN_TRUE || event == TAB_FULLSCREEN_FALSE)) 725 return true; 726 if (state == STATE_TO_NORMAL && event == TAB_FULLSCREEN_TRUE) 727 return true; 728 729 // Skip metro snap state and events when not on windows. 730#if !defined(OS_WIN) 731 if (state == STATE_METRO_SNAP || 732 event == METRO_SNAP_TRUE || 733 event == METRO_SNAP_FALSE) 734 return true; 735#endif 736 737 // Skip Mac Lion Fullscreen state and events when not on OSX 10.7+. 738 if (!SupportsMacSystemFullscreen()) { 739 if (state == STATE_BROWSER_FULLSCREEN_WITH_CHROME || 740 state == STATE_TAB_BROWSER_FULLSCREEN_CHROME || 741 state == STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME || 742 event == TOGGLE_FULLSCREEN_CHROME) { 743 return true; 744 } 745 } 746 747 return false; 748} 749 750bool FullscreenControllerStateTest::ShouldSkipTest(State state, Event event) { 751 // Quietly skip metro snap tests when not on windows. 752#if !defined(OS_WIN) 753 if (state == STATE_METRO_SNAP || 754 event == METRO_SNAP_TRUE || 755 event == METRO_SNAP_FALSE) { 756 debugging_log_ << "\nSkipping metro snap test on non-Windows.\n"; 757 return true; 758 } 759#endif 760 761 // Quietly skip Mac Lion Fullscreen tests when not on OSX 10.7+. 762 if (!SupportsMacSystemFullscreen()) { 763 if (state == STATE_BROWSER_FULLSCREEN_WITH_CHROME || 764 event == TOGGLE_FULLSCREEN_CHROME) { 765 debugging_log_ << "\nSkipping Lion Fullscreen test on non-OSX 10.7+.\n"; 766 return true; 767 } 768 } 769 770 // When testing reentrancy there are states the fullscreen controller 771 // will be unable to remain in, as they will progress due to the 772 // reentrant window change call. Skip states that will be instantly 773 // exited by the reentrant call. 774 if (IsReentrant() && (transition_table_[state][WINDOW_CHANGE] != state)) { 775 debugging_log_ << "\nSkipping reentrant test for transitory source state " 776 << GetStateString(state) << ".\n"; 777 return true; 778 } 779 780 if (ShouldSkipStateAndEventPair(state, event)) { 781 debugging_log_ << "\nSkipping test due to ShouldSkipStateAndEventPair(" 782 << GetStateString(state) << ", " 783 << GetEventString(event) << ").\n"; 784 LOG(INFO) << "Skipping test due to ShouldSkipStateAndEventPair(" 785 << GetStateString(state) << ", " 786 << GetEventString(event) << ")."; 787 return true; 788 } 789 790 return false; 791} 792 793void FullscreenControllerStateTest::TestStateAndEvent(State state, 794 Event event) { 795 if (ShouldSkipTest(state, event)) 796 return; 797 798 debugging_log_ << "\nTest transition from state " 799 << GetStateString(state) 800 << (IsReentrant() ? " with reentrant calls.\n" : ".\n"); 801 802 debugging_log_ << "First, from" 803 << GetStateString(state_) << "\n"; 804 ASSERT_NO_FATAL_FAILURE(TransitionToState(state)) 805 << GetAndClearDebugLog(); 806 807 debugging_log_ << " Then,\n"; 808 ASSERT_TRUE(InvokeEvent(event)) << GetAndClearDebugLog(); 809} 810 811FullscreenController* FullscreenControllerStateTest::GetFullscreenController() { 812 return GetBrowser()->fullscreen_controller(); 813} 814 815std::string FullscreenControllerStateTest::GetTransitionTableAsString() const { 816 std::ostringstream output; 817 output << "transition_table_[NUM_STATES = " << NUM_STATES 818 << "][NUM_EVENTS = " << NUM_EVENTS 819 << "] =\n"; 820 for (int state_int = 0; state_int < NUM_STATES; state_int++) { 821 State state = static_cast<State>(state_int); 822 output << " { // " << GetStateString(state) << ":\n"; 823 for (int event_int = 0; event_int < NUM_EVENTS; event_int++) { 824 Event event = static_cast<Event>(event_int); 825 output << " " 826 << std::left << std::setw(MAX_STATE_NAME_LENGTH+1) 827 << std::string(GetStateString(transition_table_[state][event])) + "," 828 << "// Event " 829 << GetEventString(event) << "\n"; 830 } 831 output << " },\n"; 832 } 833 output << " };\n"; 834 return output.str(); 835} 836 837std::string FullscreenControllerStateTest::GetStateTransitionsAsString() const { 838 std::ostringstream output; 839 output << "state_transitions_[NUM_STATES = " << NUM_STATES 840 << "][NUM_STATES = " << NUM_STATES << "] =\n"; 841 for (int state1_int = 0; state1_int < NUM_STATES; state1_int++) { 842 State state1 = static_cast<State>(state1_int); 843 output << "{ // " << GetStateString(state1) << ":\n"; 844 for (int state2_int = 0; state2_int < NUM_STATES; state2_int++) { 845 State state2 = static_cast<State>(state2_int); 846 const StateTransitionInfo &info = state_transitions_[state1][state2]; 847 output << " { " 848 << std::left << std::setw(MAX_EVENT_NAME_LENGTH+1) 849 << std::string(GetEventString(info.event)) + "," 850 << std::left << std::setw(MAX_STATE_NAME_LENGTH+1) 851 << std::string(GetStateString(info.state)) + "," 852 << std::right << std::setw(2) 853 << info.distance 854 << " }, // " 855 << GetStateString(state2) << "\n"; 856 } 857 output << "},\n"; 858 } 859 output << "};"; 860 return output.str(); 861} 862