File: test_browser_ui.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (186 lines) | stat: -rw-r--r-- 6,646 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/test/test_browser_ui.h"

#include "base/command_line.h"
#include "base/test/gtest_util.h"
#include "base/test/test_switches.h"
#include "build/build_config.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"

#if defined(USE_AURA)
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/window.h"
#include "ui/events/test/event_generator.h"  // nogncheck
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#endif

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
#include "content/public/common/content_switches.h"
#include "ui/base/test/skia_gold_matching_algorithm.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/test/draw_waiter_for_test.h"
#include "ui/views/test/view_skia_gold_pixel_diff.h"
#include "ui/views/widget/widget.h"
#endif

#if BUILDFLAG(IS_WIN)
#include "ui/events/platform/platform_event_source.h"
#endif

// TODO(crbug.com/40625383) support Mac for pixel tests.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
#define SUPPORTS_PIXEL_TEST
#endif

namespace {

// Extracts the |name| argument for ShowUi() from the current test case name.
// E.g. for InvokeUi_name (or DISABLED_InvokeUi_name) returns "name".
std::string NameFromTestCase() {
  const std::string name = base::TestNameWithoutDisabledPrefix(
      testing::UnitTest::GetInstance()->current_test_info()->name());
  size_t underscore = name.find('_');
  return underscore == std::string::npos ? std::string()
                                         : name.substr(underscore + 1);
}

#if defined(USE_AURA)
class ScopedMouseDisabler {
 public:
  explicit ScopedMouseDisabler(views::View* view)
      : cursor_client_(aura::client::GetCursorClient(
            view->GetWidget()->GetNativeWindow()->GetRootWindow())) {
    // Generate a mouse move event to remove any effects caused by mouse enter
    // (e.g. hover). This is necessary as hiding cursor may not emit mouse exit
    // event. (crbug.com/723535).
    ui::test::EventGenerator generator(
        view->GetWidget()->GetNativeWindow()->GetRootWindow());
    generator.MoveMouseTo({0, 0});
    cursor_client_->DisableMouseEvents();
    cursor_client_->LockCursor();
#if BUILDFLAG(IS_WIN)
    // On Windows, cursor client disable isn't consistently respected, and it's
    // also used to handle touch -> mouse event translation, so use this
    // instead. See crbug.com/333846475 for an example of the problem this
    // solves.
    ui::PlatformEventSource::SetIgnoreNativePlatformEvents(true);
#endif
  }

  ScopedMouseDisabler(const ScopedMouseDisabler&) = delete;
  const ScopedMouseDisabler operator=(const ScopedMouseDisabler&) = delete;

  ~ScopedMouseDisabler() {
#if BUILDFLAG(IS_WIN)
    ui::PlatformEventSource::SetIgnoreNativePlatformEvents(false);
#endif
    cursor_client_->UnlockCursor();
    cursor_client_->EnableMouseEvents();
  }

 private:
  raw_ptr<aura::client::CursorClient> cursor_client_;
};
#endif

}  // namespace

TestBrowserUi::TestBrowserUi() {
#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_ARM64)
  // TODO(crbug.com/40262522): Make these pass with x64 win magic numbers.
  SetPixelMatchAlgorithm(
      std::make_unique<ui::test::FuzzySkiaGoldMatchingAlgorithm>(
          /*max_different_pixels=*/1000, /*pixel_delta_threshold=*/255 * 3));
#elif defined(SUPPORTS_PIXEL_TEST)
  // Default to fuzzy diff. The magic number is chosen based on
  // past experiments.
  SetPixelMatchAlgorithm(
      std::make_unique<ui::test::FuzzySkiaGoldMatchingAlgorithm>(20, 255 * 3));
#endif
}

TestBrowserUi::~TestBrowserUi() = default;

ui::test::ActionResult TestBrowserUi::VerifyPixelUi(
    views::Widget* widget,
    const std::string& screenshot_prefix,
    const std::string& screenshot_name) {
  return VerifyPixelUi(widget->GetContentsView(), screenshot_prefix,
                       screenshot_name);
}

ui::test::ActionResult TestBrowserUi::VerifyPixelUi(
    views::View* view,
    const std::string& screenshot_prefix,
    const std::string& screenshot_name) {
#ifdef SUPPORTS_PIXEL_TEST
  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kVerifyPixels)) {
    return ui::test::ActionResult::kNotAttempted;
  }

  // Disable and hide cursor to prevent any interference with the
  // screenshots.
  ScopedMouseDisabler disable(view);

  // If there is a focused view, clear it to avoid flakiness caused by
  // unpredictable widget focus (due to test parallelism). It's important to not
  // do this unless necessary, since it will close transient UI like menus,
  // which interferes with tests attempting to verify such UI.
  if (auto* const focus_manager = view->GetWidget()->GetFocusManager();
      focus_manager->GetFocusedView()) {
    focus_manager->ClearFocus();
  }

  // Request that the compositor perform a frame and then wait for it to
  // complete. Because there might not be anything left to draw after waiting
  // for the mouse move above, request compositing so we don't wait forever.
  ui::Compositor* const compositor = view->GetWidget()->GetCompositor();
  compositor->ScheduleFullRedraw();
  ui::DrawWaiterForTest::WaitForCompositingEnded(compositor);

  views::ViewSkiaGoldPixelDiff pixel_diff(screenshot_prefix);
  bool success = pixel_diff.CompareViewScreenshot(screenshot_name, view,
                                                  GetPixelMatchAlgorithm());
  return success ? ui::test::ActionResult::kSucceeded
                 : ui::test::ActionResult::kFailed;
#else
  return ui::test::ActionResult::kKnownIncompatible;
#endif
}

void TestBrowserUi::SetPixelMatchAlgorithm(
    std::unique_ptr<ui::test::SkiaGoldMatchingAlgorithm> algorithm) {
  algorithm_ = std::move(algorithm);
}

void TestBrowserUi::ShowAndVerifyUi() {
  PreShow();
#if BUILDFLAG(IS_WIN)
  // Gold files for pixel tests are for light mode, so if dark mode is not
  // forced, and host is in dark mode, skip test.
  if (!IsInteractiveUi() &&
      !base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kForceDarkMode) &&
      ui::NativeTheme::GetInstanceForNativeUi()->ShouldUseDarkColors()) {
    GTEST_SKIP() << "Host is in dark mode; skipping test";
  }
#endif  // BUILDFLAG(IS_WIN)
  ShowUi(NameFromTestCase());
  ASSERT_TRUE(VerifyUi());
  if (IsInteractiveUi()) {
    WaitForUserDismissal();
  } else {
    DismissUi();
  }
}

bool TestBrowserUi::IsInteractiveUi() const {
  return base::CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kTestLauncherInteractive);
}