chromium/ui/wm/core/focus_controller_unittest.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/wm/core/focus_controller.h"

#include <map>

#include "base/memory/raw_ptr.h"
#include "base/test/scoped_feature_list.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/default_capture_client.h"
#include "ui/aura/client/focus_change_observer.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tracker.h"
#include "ui/base/mojom/ui_base_types.mojom-shared.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_handler.h"
#include "ui/events/test/event_generator.h"
#include "ui/wm/core/base_focus_rules.h"
#include "ui/wm/core/window_util.h"
#include "ui/wm/public/activation_change_observer.h"
#include "ui/wm/public/activation_client.h"

// EXPECT_DCHECK executes statement and expects a DCHECK death when DCHECK is
// enabled.
#if DCHECK_IS_ON()
#define EXPECT_DCHECK(statement, regex)
#else
#define EXPECT_DCHECK
#endif

namespace wm {

class FocusNotificationObserver : public ActivationChangeObserver,
                                  public aura::client::FocusChangeObserver {};

class WindowDeleter {};

// ActivationChangeObserver and FocusChangeObserver that keeps track of whether
// it was notified about activation changes or focus changes with a deleted
// window.
class RecordingActivationAndFocusChangeObserver
    : public ActivationChangeObserver,
      public aura::client::FocusChangeObserver {};

// Hides a window when activation changes.
class HideOnLoseActivationChangeObserver : public ActivationChangeObserver {};

// ActivationChangeObserver that deletes the window losing activation.
class DeleteOnActivationChangeObserver : public ActivationChangeObserver,
                                         public WindowDeleter {};

// FocusChangeObserver that deletes the window losing focus.
class DeleteOnLoseFocusChangeObserver
    : public aura::client::FocusChangeObserver,
      public WindowDeleter {};

class ScopedFocusNotificationObserver : public FocusNotificationObserver {};

class ScopedTargetFocusNotificationObserver : public FocusNotificationObserver {};

// Used to fake the handling of events in the pre-target phase.
class SimpleEventHandler : public ui::EventHandler {};

class FocusShiftingActivationObserver : public ActivationChangeObserver {};

class ActivateWhileActivatingObserver : public ActivationChangeObserver {};

// BaseFocusRules subclass that allows basic overrides of focus/activation to
// be tested. This is intended more as a test that the override system works at
// all, rather than as an exhaustive set of use cases, those should be covered
// in tests for those FocusRules implementations.
class TestFocusRules : public BaseFocusRules {};

// Common infrastructure shared by all FocusController test types.
class FocusControllerTestBase : public aura::test::AuraTestBase {};

// Test base for tests where focus is directly set to a target window.
class FocusControllerDirectTestBase : public FocusControllerTestBase {};

// Focus and Activation changes via ActivationClient API.
class FocusControllerApiTest : public FocusControllerDirectTestBase {};

// Focus and Activation changes via input events.
class FocusControllerMouseEventTest : public FocusControllerDirectTestBase {};

class FocusControllerMouseEnterEventTest
    : public FocusControllerMouseEventTest {};

class FocusControllerGestureEventTest : public FocusControllerDirectTestBase {};

// Test base for tests where focus is implicitly set to a window as the result
// of a disposition change to the focused window or the hierarchy that contains
// it.
class FocusControllerImplicitTestBase : public FocusControllerTestBase {};

// Focus and Activation changes in response to window visibility changes.
class FocusControllerHideTest : public FocusControllerImplicitTestBase {};

// Focus and Activation changes in response to window parent visibility
// changes.
class FocusControllerParentHideTest : public FocusControllerHideTest {};

// Focus and Activation changes in response to window destruction.
class FocusControllerDestructionTest : public FocusControllerImplicitTestBase {};

// Focus and Activation changes in response to window parent destruction.
class FocusControllerParentDestructionTest
    : public FocusControllerDestructionTest {};

// Focus and Activation changes in response to window removal.
class FocusControllerRemovalTest : public FocusControllerImplicitTestBase {};

// Focus and Activation changes in response to window parent removal.
class FocusControllerParentRemovalTest : public FocusControllerRemovalTest {};

#define FOCUS_CONTROLLER_TEST(TESTCLASS, TESTNAME)

// Runs direct focus change tests (input events and API calls).
#define DIRECT_FOCUS_CHANGE_TESTS(TESTNAME)

// Runs implicit focus change tests for disposition changes to target.
#define IMPLICIT_FOCUS_CHANGE_TARGET_TESTS(TESTNAME)

// Runs implicit focus change tests for disposition changes to target's parent
// hierarchy.
#define IMPLICIT_FOCUS_CHANGE_PARENT_TESTS(TESTNAME)

// Runs all implicit focus change tests (changes to the target and target's
// parent hierarchy)
#define IMPLICIT_FOCUS_CHANGE_TESTS(TESTNAME)

// Runs all possible focus change tests.
#define ALL_FOCUS_TESTS(TESTNAME)

// Runs focus change tests that apply only to the target. For example,
// implicit activation changes caused by window disposition changes do not
// occur when changes to the containing hierarchy happen.
#define TARGET_FOCUS_TESTS(TESTNAME)

// - Focuses a window, verifies that focus changed.
ALL_FOCUS_TESTS(BasicFocus)

// - Activates a window, verifies that activation changed.
TARGET_FOCUS_TESTS(BasicActivation)

// - Focuses a window, verifies that focus events were dispatched.
ALL_FOCUS_TESTS(FocusEvents)

// - Focuses or activates a window multiple times, verifies that events are only
//   dispatched when focus/activation actually changes.
DIRECT_FOCUS_CHANGE_TESTS(DuplicateFocusEvents)
DIRECT_FOCUS_CHANGE_TESTS(DuplicateActivationEvents)

// - Activates a window, verifies that activation events were dispatched.
TARGET_FOCUS_TESTS(ActivationEvents)

// - Attempts to active a hidden window, verifies that current window is
//   attempted to be reactivated and the appropriate event dispatched.
FOCUS_CONTROLLER_TEST(FocusControllerApiTest, ReactivationEvents)

// - Input events/API calls shift focus between focusable windows within the
//   active window.
DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusWithinActiveWindow)

// - Input events/API calls to a child window of an inactive window shifts
//   activation to the activatable parent and focuses the child.
DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusToChildOfInactiveWindow)

// - Input events/API calls to focus the parent of the focused window do not
//   shift focus away from the child.
DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusToParentOfFocusedWindow)

// - Verifies that FocusRules determine what can be focused.
ALL_FOCUS_TESTS(FocusRulesOverride)

// - Verifies that FocusRules determine what can be activated.
TARGET_FOCUS_TESTS(ActivationRulesOverride)

// - Verifies that attempts to change focus or activation from a focus or
//   activation change observer are ignored.
DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusOnActivation)
DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusOnActivationDueToHide)
DIRECT_FOCUS_CHANGE_TESTS(NoShiftActiveOnActivation)

FOCUS_CONTROLLER_TEST(FocusControllerApiTest, FocusChangeDuringDrag)

FOCUS_CONTROLLER_TEST(FocusControllerApiTest,
                      ChangeFocusWhenNothingFocusedAndCaptured)

// See description above DontPassDeletedWindow() for details.
FOCUS_CONTROLLER_TEST(FocusControllerApiTest, DontPassDeletedWindow)

FOCUS_CONTROLLER_TEST(FocusControllerApiTest, StackWindowAtTopOnActivation)

FOCUS_CONTROLLER_TEST(FocusControllerApiTest,
                      HideFocusedWindowDuringActivationLoss)

FOCUS_CONTROLLER_TEST(FocusControllerApiTest, ActivateWhileActivating)

// See description above TransientChildWindowActivationTest() for details.
FOCUS_CONTROLLER_TEST(FocusControllerParentHideTest,
                      TransientChildWindowActivationTest)

// If a mouse event was handled, it should not activate a window.
FOCUS_CONTROLLER_TEST(FocusControllerMouseEventTest, IgnoreHandledEvent)

// Mouse over window should activate it.
FOCUS_CONTROLLER_TEST(FocusControllerMouseEnterEventTest, MouseEnteredEvent)

// Mouse over window with active parent should not focus it.
FOCUS_CONTROLLER_TEST(FocusControllerMouseEnterEventTest,
                      MouseEnteredWithActiveParent)

}  // namespace wm