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#ifndef CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_STATE_TEST_H_
6#define CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_STATE_TEST_H_
7
8#include <sstream>
9
10#include "base/basictypes.h"
11#include "base/compiler_specific.h"
12#include "base/memory/scoped_ptr.h"
13#include "build/build_config.h"
14
15class Browser;
16class FullscreenController;
17class FullscreenNotificationObserver;
18
19// Utility definition for mapping enum values to strings in switch statements.
20#define ENUM_TO_STRING(enum) case enum: return #enum
21
22// Test fixture used to test Fullscreen Controller through exhaustive sequences
23// of events in unit and interactive tests.
24//
25// Because operating system window managers are too unreliable (they result in
26// flakiness at around 1 out of 1000 runs) this fixture is designed to be run
27// on testing infrastructure in unit tests mocking out the platforms' behavior.
28// To verify that behavior interactive tests exist but are left disabled and
29// only run manually when verifying the consistency of the
30// FullscreenControllerTestWindow.
31class FullscreenControllerStateTest {
32 public:
33  // Events names for FullscreenController methods.
34  enum Event {
35    TOGGLE_FULLSCREEN,         // ToggleBrowserFullscreenMode()
36    TOGGLE_FULLSCREEN_CHROME,  // ToggleBrowserFullscreenWithChrome()
37    TAB_FULLSCREEN_TRUE,       // ToggleFullscreenModeForTab(, true)
38    TAB_FULLSCREEN_FALSE,      // ToggleFullscreenModeForTab(, false)
39    METRO_SNAP_TRUE,           // SetMetroSnapMode(true)
40    METRO_SNAP_FALSE,          // SetMetroSnapMode(false)
41    BUBBLE_EXIT_LINK,          // ExitTabOrBrowserFullscreenToPreviousState()
42    BUBBLE_ALLOW,              // OnAcceptFullscreenPermission()
43    BUBBLE_DENY,               // OnDenyFullscreenPermission()
44    WINDOW_CHANGE,             // ChangeWindowFullscreenState()
45    NUM_EVENTS,
46    EVENT_INVALID,
47  };
48
49  // Conceptual states of the Fullscreen Controller, these do not correspond
50  // to particular implemenation details.
51  enum State {
52    // The window is not in fullscreen.
53    STATE_NORMAL,
54    // User-initiated fullscreen.
55    STATE_BROWSER_FULLSCREEN_NO_CHROME,
56    // Mac User-initiated 'Lion Fullscreen' with browser chrome. OSX 10.7+ only.
57    STATE_BROWSER_FULLSCREEN_WITH_CHROME,
58    // Windows 8 Metro Snap mode, which puts the window at 20% screen-width.
59    // No TO_ state for Metro, as the windows implementation is only reentrant.
60    STATE_METRO_SNAP,
61    // HTML5 tab-initiated fullscreen.
62    STATE_TAB_FULLSCREEN,
63    // Both tab and browser fullscreen.
64    STATE_TAB_BROWSER_FULLSCREEN,
65    // Both tab and browser fullscreen, displayed without chrome, but exits tab
66    // fullscreen to STATE_BROWSER_FULLSCREEN_WITH_CHROME.
67    STATE_TAB_BROWSER_FULLSCREEN_CHROME,
68    // TO_ states are asynchronous states waiting for window state change
69    // before transitioning to their named state.
70    STATE_TO_NORMAL,
71    STATE_TO_BROWSER_FULLSCREEN_NO_CHROME,
72    STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME,
73    STATE_TO_TAB_FULLSCREEN,
74    NUM_STATES,
75    STATE_INVALID,
76  };
77
78  static const int kMaxStateNameLength = 39;
79  static const int kMaxEventNameLength = 24;
80
81  FullscreenControllerStateTest();
82  virtual ~FullscreenControllerStateTest();
83
84  static const char* GetStateString(State state);
85  static const char* GetEventString(Event event);
86
87  // Returns true if FullscreenController::WindowFullscreenStateChanged()
88  // will be called and re-enter FullscreenController before
89  // FullscreenController methods complete.
90  static bool IsWindowFullscreenStateChangedReentrant();
91
92  // Returns true if |state| can be persistent. This is true for all of the
93  // states without "_TO_" in their name.
94  static bool IsPersistentState(State state);
95
96  // Causes Fullscreen Controller to transition to an arbitrary state.
97  void TransitionToState(State state);
98
99  // Makes one state change to approach |destination_state| via shortest path.
100  // Returns true if a state change is made.
101  // Repeated calls are needed to reach the destination.
102  bool TransitionAStepTowardState(State destination_state);
103
104  // Calls FullscreenController::ChangeWindowFullscreenState if needed because
105  // a mock BrowserWindow is being used.
106  virtual void ChangeWindowFullscreenState() {}
107
108  // Returns a description of the window's state, may return NULL.
109  // FullscreenControllerStateTest owns the returned pointer.
110  virtual const char* GetWindowStateString();
111
112  // Causes the |event| to occur and return true on success.
113  virtual bool InvokeEvent(Event event);
114
115  // Checks that window state matches the expected controller state.
116  virtual void VerifyWindowState();
117
118  // Wait for NOTIFICATION_FULLSCREEN_CHANGED if a notification should have been
119  // sent in transitioning to |state_| from the previous persistent state.
120  void MaybeWaitForNotification();
121
122  // Tests all states with all permutations of multiple events to detect
123  // lingering state issues that would bleed over to other states.
124  // I.E. for each state test all combinations of events E1, E2, E3.
125  //
126  // This produces coverage for event sequences that may happen normally but
127  // would not be exposed by traversing to each state via TransitionToState().
128  // TransitionToState() always takes the same path even when multiple paths
129  // exist.
130  void TestTransitionsForEachState();
131
132  // Log transition_table_ to a string for debugging.
133  std::string GetTransitionTableAsString() const;
134  // Log state_transitions_ to a string for debugging.
135  std::string GetStateTransitionsAsString() const;
136
137 protected:
138  // Set of enumerations (created with a helper macro) for _FALSE, _TRUE, and
139  // _NO_EXPECTATION values to be passed to VerifyWindowStateExpectations().
140  #define EXPECTATION_ENUM(enum_name, enum_prefix) \
141      enum enum_name { \
142        enum_prefix##_FALSE, \
143        enum_prefix##_TRUE, \
144        enum_prefix##_NO_EXPECTATION \
145      }
146  EXPECTATION_ENUM(FullscreenWithChromeExpectation, FULLSCREEN_WITH_CHROME);
147  EXPECTATION_ENUM(FullscreenWithoutChromeExpectation,
148                   FULLSCREEN_WITHOUT_CHROME);
149  EXPECTATION_ENUM(FullscreenForBrowserExpectation, FULLSCREEN_FOR_BROWSER);
150  EXPECTATION_ENUM(FullscreenForTabExpectation, FULLSCREEN_FOR_TAB);
151  EXPECTATION_ENUM(InMetroSnapExpectation, IN_METRO_SNAP);
152
153  // Generated information about the transitions between states.
154  struct StateTransitionInfo {
155    StateTransitionInfo()
156        : event(EVENT_INVALID),
157          state(STATE_INVALID),
158          distance(NUM_STATES) {}
159    Event event;  // The |Event| that will cause the state transition.
160    State state;  // The adjacent |State| transitioned to; not the final state.
161    int distance;  // Steps to final state. NUM_STATES represents unknown.
162  };
163
164  // Returns next transition info for shortest path from source to destination.
165  StateTransitionInfo NextTransitionInShortestPath(State source,
166                                                   State destination,
167                                                   int search_limit);
168
169  // Returns a detailed log of what FullscreenControllerStateTest has done
170  // up to this point, to be reported when tests fail.
171  std::string GetAndClearDebugLog();
172
173  // Returns true if the |state| & |event| pair should be skipped.
174  virtual bool ShouldSkipStateAndEventPair(State state, Event event);
175
176  // Returns true if a test should be skipped entirely, e.g. due to platform.
177  virtual bool ShouldSkipTest(State state, Event event);
178
179  // Runs one test of transitioning to a state and invoking an event.
180  virtual void TestStateAndEvent(State state, Event event);
181
182  // Checks that window state matches the expected controller state.
183  virtual void VerifyWindowStateExpectations(
184      FullscreenWithChromeExpectation fullscreen_with_chrome,
185      FullscreenWithoutChromeExpectation fullscreen_without_chrome,
186      FullscreenForBrowserExpectation fullscreen_for_browser,
187      FullscreenForTabExpectation fullscreen_for_tab,
188      InMetroSnapExpectation in_metro_snap);
189
190
191  virtual Browser* GetBrowser() = 0;
192  FullscreenController* GetFullscreenController();
193
194  // The state the FullscreenController is expected to be in.
195  State state() const { return state_; }
196
197 private:
198  // The state the FullscreenController is expected to be in.
199  State state_;
200
201  // The state when the previous NOTIFICATION_FULLSCREEN_CHANGED notification
202  // was received.
203  State last_notification_received_state_;
204
205  // Listens for the NOTIFICATION_FULLSCREEN_CHANGED notification.
206  scoped_ptr<FullscreenNotificationObserver> fullscreen_notification_observer_;
207
208  // Human defined |State| that results given each [state][event] pair.
209  State transition_table_[NUM_STATES][NUM_EVENTS];
210
211  // Generated information about the transitions between states [from][to].
212  // View generated data with: out/Release/unit_tests
213  //     --gtest_filter="FullscreenController*DebugLogStateTables"
214  //     --gtest_also_run_disabled_tests
215  StateTransitionInfo state_transitions_[NUM_STATES][NUM_STATES];
216
217  // Log of operations reported on errors via GetAndClearDebugLog().
218  std::ostringstream debugging_log_;
219
220  DISALLOW_COPY_AND_ASSIGN(FullscreenControllerStateTest);
221};
222
223#endif  // CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_STATE_TEST_H_
224