chromium/chrome/browser/ash/accessibility/accessibility_test_utils.h

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

#ifndef CHROME_BROWSER_ASH_ACCESSIBILITY_ACCESSIBILITY_TEST_UTILS_H_
#define CHROME_BROWSER_ASH_ACCESSIBILITY_ACCESSIBILITY_TEST_UTILS_H_

#include <string>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/statistics_recorder.h"
#include "base/run_loop.h"
#include "chrome/browser/extensions/error_console/error_console.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "ui/base/ime/input_method_base.h"
#include "ui/base/ime/input_method_observer.h"

namespace ash {

using ContextType = ::extensions::ExtensionBrowserTest::ContextType;
using ::extensions::ErrorConsole;

enum class ManifestVersion { kTwo, kThree };
class FullscreenMagnifierController;

// A class used to define the parameters of an API test case.
class ApiTestConfig {
 public:
  ApiTestConfig(ContextType context_type, ManifestVersion version)
      : context_type_(context_type), version_(version) {}

  ContextType context_type() const { return context_type_; }
  ManifestVersion version() const { return version_; }

 private:
  ContextType context_type_;
  ManifestVersion version_;
};

// A class that waits for caret bounds changed.
class CaretBoundsChangedWaiter : public ui::InputMethodObserver {
 public:
  explicit CaretBoundsChangedWaiter(ui::InputMethod* input_method);
  CaretBoundsChangedWaiter(const CaretBoundsChangedWaiter&) = delete;
  CaretBoundsChangedWaiter& operator=(const CaretBoundsChangedWaiter&) = delete;
  ~CaretBoundsChangedWaiter() override;

  // Waits for bounds changed within the input method.
  void Wait();

 private:
  // ui::InputMethodObserver:
  void OnFocus() override {}
  void OnBlur() override {}
  void OnTextInputStateChanged(const ui::TextInputClient* client) override {}
  void OnInputMethodDestroyed(const ui::InputMethod* input_method) override {}
  void OnCaretBoundsChanged(const ui::TextInputClient* client) override;

  raw_ptr<ui::InputMethod> input_method_;
  base::RunLoop run_loop_;
};

// Instantiate this class to get errors and warnings for an extension.
// This will catch console.error and console.warn messages as well as
// any uncaught JS errors in the extension and cause a non-fatal
// test failure as well as log the failure message.
//
// If this is used in the test SetUp, ensure the lifecycle lasts past
// the scope of the SetUp method, perhaps by using a member var, e.g.
// console_observer_ = std::make_unique<ExtensionConsoleErrorObserver>(
//        browser()->profile(), extension_misc::kSelectToSpeakExtensionId);
class ExtensionConsoleErrorObserver : public ErrorConsole::Observer {
 public:
  ExtensionConsoleErrorObserver(Profile* profile, const char* extension_id);
  virtual ~ExtensionConsoleErrorObserver();

  // ErrorConsole::Observer:
  void OnErrorAdded(const extensions::ExtensionError* error) override;
  void OnErrorConsoleDestroyed() override;

  // Returns whether errors or warnings were received.
  bool HasErrorsOrWarnings();

  // A helper method to return the string content (in UTF8) of the error or
  // warning at the given |index|. This will cause a test failure if there is no
  // such message.
  std::string GetErrorOrWarningAt(size_t index) const;

  // Get the number of errors and warnings received.
  size_t GetErrorsAndWarningsCount() const;

 private:
  std::vector<std::u16string> errors_;
  raw_ptr<ErrorConsole> error_console_;
};

// Listens for changes to the histogram provided at construction. This class
// only allows `Wait()` to be called once. If you need to call `Wait()` multiple
// times, create multiple instances of this class.
class HistogramWaiter {
 public:
  explicit HistogramWaiter(const char* metric_name);
  ~HistogramWaiter();
  HistogramWaiter(const HistogramWaiter&) = delete;
  HistogramWaiter& operator=(const HistogramWaiter&) = delete;

  // Waits for the next update to the observed histogram.
  void Wait();
  void OnHistogramCallback(const char* metric_name,
                           uint64_t name_hash,
                           base::HistogramBase::Sample sample);

 private:
  std::unique_ptr<base::StatisticsRecorder::ScopedHistogramSampleObserver>
      histogram_observer_;
  base::RunLoop run_loop_;
};

// FullscreenMagnifierController moves the magnifier window with animation
// when the magnifier is set to be enabled. This waiter class lets a consumer
// wait until the animation completes, i.e. after a mouse move.
class MagnifierAnimationWaiter {
 public:
  explicit MagnifierAnimationWaiter(FullscreenMagnifierController* controller);

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

  ~MagnifierAnimationWaiter();

  // Wait until the Fullscreen magnifier finishes animating.
  void Wait();

 private:
  void OnTimer();

  raw_ptr<FullscreenMagnifierController> controller_;  // not owned
  scoped_refptr<content::MessageLoopRunner> runner_;
};

}  // namespace ash
#endif  // CHROME_BROWSER_ASH_ACCESSIBILITY_ACCESSIBILITY_TEST_UTILS_H_