// Copyright 2022 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef UI_BASE_INTERACTION_INTERACTIVE_TEST_INTERNAL_H_ #define UI_BASE_INTERACTION_INTERACTIVE_TEST_INTERNAL_H_ #include <concepts> #include <functional> #include <memory> #include <string> #include <string_view> #include <tuple> #include <type_traits> #include <variant> #include "base/callback_list.h" #include "base/containers/contains.h" #include "base/functional/callback_helpers.h" #include "base/gtest_prod_util.h" #include "base/logging.h" #include "base/no_destructor.h" #include "base/strings/strcat.h" #include "base/test/bind.h" #include "base/test/rectify_callback.h" #include "base/types/is_instantiation.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/interaction/element_identifier.h" #include "ui/base/interaction/element_test_util.h" #include "ui/base/interaction/element_tracker.h" #include "ui/base/interaction/framework_specific_implementation.h" #include "ui/base/interaction/interaction_sequence.h" #include "ui/base/interaction/interaction_test_util.h" #include "ui/base/interaction/state_observer.h" namespace ui::test { class InteractiveTestApi; class InteractiveTestTest; namespace internal { // Element that is present during interactive tests that actions can bounce // events off of. DECLARE_ELEMENT_IDENTIFIER_VALUE(…); DECLARE_CUSTOM_ELEMENT_EVENT_TYPE(…); extern const char kInteractiveTestFailedMessagePrefix[]; extern const char kNoCheckDescriptionSpecified[]; class StateObserverElement; // Class that implements functionality for InteractiveTest* that should be // hidden from tests that inherit the API. class InteractiveTestPrivate { … }; // Specifies an element either by ID or by name. ElementSpecifier; class StateObserverElement : public TestElementBase { … }; // Implements an element that is shown when an observed state matches a desired // value or pattern, and hidden when it does not. template <typename T> class StateObserverElementT : public StateObserverElement { … }; // Applies `matcher` to `value` and returns the result; on failure a useful // error message is printed using `test_name`, `value`, and `matcher`. // // Steps which use this method will fail if it returns false, printing out the // details of the step in the usual way. template <typename T, typename V = std::decay_t<T>> bool MatchAndExplain(std::string_view test_name, const testing::Matcher<V>& matcher, const T& value) { … } template <typename Observer, typename V> bool InteractiveTestPrivate::AddStateObserver( ElementIdentifier id, ElementContext context, std::unique_ptr<Observer> state_observer) { … } // Similar to `std::invocable<T, Args...>`, but does not put constraints on the // parameters passed to the invocation method. IsCallable; // Applies if `T` has bound state (such as a lambda expression with captures). HasState; // Helper for matching a function pointer. IsFunctionPointerValue; IsFunctionPointerValue; // Applies if `T` is a function pointer (but not a pointer to an instance // member function). IsFunctionPointer; // Optionally converts `function` to something that is compatible with a // base::OnceCallback. template <typename F> auto MaybeBind(F&& function) { … } // Helper struct that captures information about what signature a function-like // object would have if it were bound. template <typename F> struct MaybeBindTypeHelper { … }; // DoNothing always has a void return type but no defined signature. template <> struct MaybeBindTypeHelper<decltype(base::DoNothing())> { … }; // Optionally converts `function` to something that is compatible with a // base::RepeatingCallback, or returns it as-is if it's already a callback. template <typename F> base::RepeatingCallback<typename MaybeBindTypeHelper<F>::Signature> MaybeBindRepeating(F&& function) { … } template <typename T> struct ArgsExtractor; ArgsExtractor<R (Args...)>; ReturnTypeOf; NthArgumentOf; // Requires that `F` resolves to some kind of callable object with call // signature `S`. HasSignature; // Helper for `HasCompatibleSignature`; see recursive implementation below. HasCompatibleSignatureValue; // Requires that `F` resolves to some kind of callable object whose signature // can be rectified to `S`; see `base::RectifyCallback` for more information. // (Basically, `F` can omit arguments from the left of `S`; these arguments // will be ignored.) HasCompatibleSignature; // This is the leaf state for the recursive compatibility computation; see // below. HasCompatibleSignatureValue; // Implementation for `HasCompatibleSignature`. // // This removes arguments one by one from the left of the target signature `S` // to see if `F` has that signature. The recursion stops when one matches, or // when the arg list is empty (in which case the leaf state is hit, above). HasCompatibleSignatureValue; // Checks that `T` is a reference wrapper around any type. IsReferenceWrapper; // Helper to determine the type used to match a value. The default is to just // use the decayed value type. template <typename T> struct MatcherTypeHelper { … }; // Specialization for string types used in Chrome. For any representation of a // string using character type, the type used for matching is the corresponding // `std::basic_string`. // // Add to this template if different character formats become supported (e.g. // char8_t, char32_t, wchar_t, etc.) MatcherTypeHelper<C *>; // Gets the appropriate matchable type for `T`. This affects string-like types // (e.g. `const char*`) as the corresponding `Matcher` should match a // `std::string` or `std::u16string`. MatcherTypeFor; // Determines if `T` is a valid type to be used in a matcher. This precludes // string-like types (const char*, constexpr char16_t[], etc.) in favor of // `std::string` and `std::u16string`. IsValidMatcherType; IsGtestMatcher; HasMatchAndExplain; IsMatcher; // Accepts any function-like object that is compatible with // `InteractionSequence::StepCallback`. IsStepCallback; // Accepts any function-like object that can be used with `Check()` and // `CheckResult()`. IsCheckCallback; // Converts an ElementSpecifier to an element ID or name and sets it onto // `builder`. void SpecifyElement(ui::InteractionSequence::StepBuilder& builder, ElementSpecifier element); std::string DescribeElement(ElementSpecifier spec); InteractionSequence::Builder BuildSubsequence( InteractiveTestPrivate::MultiStep steps); // Takes an argument expected to be a literal value and retrieves the literal // value by either calling the object (if it's callable), unwrapping it (if it's // a `std::reference_wrapper`) or just returning it otherwise. // // This allows e.g. passing deferred or computed values to the `Log()` verb. template <typename Arg> auto UnwrapArgument(Arg arg) { … } } // namespace internal } // namespace ui::test #endif // UI_BASE_INTERACTION_INTERACTIVE_TEST_INTERNAL_H_