chromium/components/exo/wayland/test/wlcs/wlcs_helpers.h

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

#ifndef COMPONENTS_EXO_WAYLAND_TEST_WLCS_WLCS_HELPERS_H_
#define COMPONENTS_EXO_WAYLAND_TEST_WLCS_WLCS_HELPERS_H_

#include <wayland-client-core.h>
#include <wayland-server-core.h>

#include "base/at_exit.h"
#include "base/containers/flat_map.h"
#include "components/exo/wayland/fuzzer/server_environment.h"

namespace exo::wayland {
class Server;
}

namespace ui::test {
class EventGenerator;
}

namespace exo::wlcs {

// WlcsInitializer is an object that simply calls some static initialization
// code in its constructor. This allows us to use member initialization order to
// guaranteed the static initialization occurs at the correct time.
class WlcsInitializer {
 public:
  WlcsInitializer();
};

// WlcsEnvironment holds the handles to all the runtime objects used across
// tests (i.e. that outlive the test).
//
// This class has a global singleton instance accessible via Get().
class WlcsEnvironment {
 public:
  static WlcsEnvironment& Get();

  base::AtExitManager exit_manager;
  WlcsInitializer initializer;
  wayland_fuzzer::ServerEnvironment env;

 private:
  WlcsEnvironment();
  ~WlcsEnvironment();
};

// Scoped object which allows WLCS to create/destroy exo's servers based on the
// lifetime of this object.
//
// Additionally, this class keeps track of wayland clients created for its
// server to facilitate associating wl_proxy objects with their server-side
// resource.
class ScopedWlcsServer {
 public:
  explicit ScopedWlcsServer();
  ~ScopedWlcsServer();

  wayland::Server* Get() const;

  // Add a wayland client, returning an FD which connects to the server, or -1
  // on error.
  //
  // Additionally, clients created this way will be tracked, allowing the user
  // to call ObjectToResource() to get server-side handles for this client's
  // objects.
  int AddClient();

  wl_resource* ProxyToResource(struct wl_display* client_display,
                               wl_proxy* client_side_proxy) const;

  // Returns the server-side wl_resource associated with the provided
  // client_object (all client-side wayland objects are opaquely backed by
  // wl_proxy).
  template <typename Obj>
  wl_resource* ObjectToResource(struct wl_display* client_display,
                                Obj client_object) const {
    // Wayland interfaces are basically transparent types that get created by
    // casting a wl_proxy to the relevant struct name, so it is safe to undo
    // that with reinterpret_cast().
    return ProxyToResource(client_display,
                           reinterpret_cast<wl_proxy*>(client_object));
  }

  // Convenience method for generating ui events. This method will run the given
  // |invocation| on the UI thread with the correct event generator, in a
  // blocking fashion.
  //
  // TODO(b/276660692): prefer ui_controls over ui::test::EventGenerator due to
  // the former's increased coverage. We didn't do so for now due to some
  // missing APIs.
  void GenerateEvent(
      base::OnceCallback<void(ui::test::EventGenerator&)> invocation);

 private:
  base::flat_map<int, wl_client*> fd_to_client_;

  std::unique_ptr<ui::test::EventGenerator> evg_;
};

}  // namespace exo::wlcs

#endif  // COMPONENTS_EXO_WAYLAND_TEST_WLCS_WLCS_HELPERS_H_