AUI Framework  master
Cross-platform module-based framework for developing C++20 desktop applications
UIMatcher.h
1/*
2 * AUI Framework - Declarative UI toolkit for modern C++20
3 * Copyright (C) 2020-2024 Alex2772 and Contributors
4 *
5 * SPDX-License-Identifier: MPL-2.0
6 *
7 * This Source Code Form is subject to the terms of the Mozilla Public
8 * License, v. 2.0. If a copy of the MPL was not distributed with this
9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 */
11
12#pragma once
13
14
15#include "IMatcher.h"
16#include <gtest/gtest.h>
17#include <AUI/Test/UI/Assertion/Empty.h>
18#include <AUI/View/AViewContainer.h>
19#include "UITestUtil.h"
20
21class API_AUI_UITESTS UIMatcher {
22private:
23 _<IMatcher> mMatcher;
24 bool mIncludeInvisibleViews = false;
25
26
27 void processContainer(ASet<_<AView>>& destination, const _<AViewContainerBase>& container) const;
28
29 template<typename T, typename = int>
30 struct ignores_visibility : std::false_type { };
31
32 template<typename T>
33 struct ignores_visibility<T, decltype((T::IGNORE_VISIBILITY::value, 0))> : T::IGNORE_VISIBILITY { };
34
35 template<class Assertion>
36 void performHintChecks(const char* msg, ASet<_<AView>>& set) {
37 currentImpl() = this;
38 if constexpr (ignores_visibility<Assertion>::value) {
39 set = toSet();
40 }
41 uitest::frame();
42 if (msg == nullptr) std::cout << "Assertion message is empty";
43 if constexpr(!std::is_same_v<Assertion, empty>) {
44 if (set.empty()) std::cout << "UIMatcher is empty so check is not performed";
45 }
46 }
47
48 static UIMatcher*& currentImpl();
49
50public:
51 UIMatcher(const _<IMatcher>& matcher) : mMatcher(matcher) {}
52
53 ~UIMatcher() {
54 if (current() == this) {
55 currentImpl() = nullptr;
56 }
57 }
58
59 static UIMatcher* current() {
60 return currentImpl();
61 }
62
63 ASet<_<AView>> toSet() const;
64
65 _<AView> one() const {
66 auto set = toSet();
67 if (set.empty()) {
68 SCOPED_TRACE("no views selected");
69 return nullptr;
70 }
71 return *set.begin();
72 }
73
74 UIMatcher& includeInvisibleViews() {
75 mIncludeInvisibleViews = true;
76 return *this;
77 }
78
79 template<class Action>
80 UIMatcher& perform(Action&& action) {
81 auto set = toSet();
82 if (set.empty()) std::cout << "UIMatcher is empty so action is not performed";
83
84 uitest::frame();
85 for (auto& v : set) {
86 action(v);
87 uitest::frame();
88 }
89 return *this;
90 }
91
112 auto mySet = toSet();
113 auto targets = matcher.toSet();
114
115 if (targets.size() != 1) {
116 throw AException("expected to match one view, matched {}"_format(mySet.size()));
117 }
118 if (mySet.empty()) {
119 throw AException("findNearestTo requires at least one element to match");
120 }
121
122 auto nearestToView = (*targets.begin());
123 auto nearestToPoint = glm::vec2(nearestToView->getPositionInWindow() + nearestToView->getSize());
124 auto target = std::min_element(mySet.begin(), mySet.end(), [&](const _<AView>& lhs, const _<AView>& rhs) {
125 float dst1 = glm::distance2(nearestToPoint, glm::vec2(lhs->getCenterPointInWindow()));
126 float dst2 = glm::distance2(nearestToPoint, glm::vec2(rhs->getCenterPointInWindow()));
127 return dst1 < dst2;
128 });
129 EXPECT_TRUE(target != mySet.end());
130
131 class ToOneMatcher: public IMatcher {
132 public:
133 explicit ToOneMatcher(_<AView> view) : mView(std::move(view)) {}
134
135 bool matches(const _<AView>& view) override {
136 return view == mView;
137 }
138 private:
139 _<AView> mView;
140 };
141
142 return { _new<ToOneMatcher>(std::move(*target)) };
143 }
144
145
146 template<class Assertion>
147 UIMatcher& check(Assertion&& assertion, const char* msg = "no msg") {
148 mIncludeInvisibleViews = ignores_visibility<Assertion>::value;
149 auto set = toSet();
150 EXPECT_FALSE(set.empty()) << msg << ": empty set\n" << AStacktrace::capture(1);
151
152 performHintChecks<Assertion>(msg, set);
153 for (auto& s : set) {
154 EXPECT_TRUE(assertion(s)) << msg << "\n" << AStacktrace::capture(1);
155 }
156 return *this;
157 }
158
159 [[nodiscard]]
160 UIMatcher parent() const {
161
162 struct ParentMatcher: public IMatcher {
163 private:
164 _<IMatcher> childMatcher;
165 public:
166 ParentMatcher(const _<IMatcher>& childMatcher) : childMatcher(childMatcher) {}
167
168 bool matches(const _<AView>& view) override {
169 if (auto container = _cast<AViewContainer>(view)) {
170 for (const auto& childView : container) {
171 if (childMatcher->matches(childView)) return true;
172 }
173 }
174 return false;
175 }
176 };
177 return { _new<ParentMatcher>(mMatcher) };
178 }
179
180 [[nodiscard]]
181 UIMatcher allChildren() const {
182
183 struct ChildMatcher: public IMatcher {
184 private:
185 _<IMatcher> childMatcher;
186 public:
187 ChildMatcher(const _<IMatcher>& childMatcher) : childMatcher(childMatcher) {}
188
189 bool matches(const _<AView>& view) override {
190 return childMatcher->matches(aui::ptr::fake(view->getParent()));
191 }
192 };
193
194 return { _new<ChildMatcher>(mMatcher) };
195 }
196
197private:
198
199 template<class BinaryOperator>
200 struct BinaryOperatorMatcher: public IMatcher {
201 private:
202 _<IMatcher> lhs;
203 _<IMatcher> rhs;
204 public:
205 BinaryOperatorMatcher(const _<IMatcher>& lhs, const _<IMatcher>& rhs) : lhs(lhs), rhs(rhs) {}
206
207 bool matches(const _<AView>& view) override {
208 return BinaryOperator()(lhs->matches(view), rhs->matches(view));
209 }
210 };
211
212public:
213
214 UIMatcher operator|(const UIMatcher& matcher) const {
215 struct compare_or {
216 bool operator()(bool lhs, bool rhs) const {
217 return lhs || rhs;
218 }
219 };
220 return { _new<BinaryOperatorMatcher<compare_or>>(mMatcher, matcher.mMatcher) };
221 }
222
223 UIMatcher operator&(const UIMatcher& matcher) const {
224 struct compare_and {
225 bool operator()(bool lhs, bool rhs) const {
226 return lhs && rhs;
227 }
228 };
229 return { _new<BinaryOperatorMatcher<compare_and>>(mMatcher, matcher.mMatcher) };
230 }
231};
232
233
Abstract AUI exception.
Definition: AException.h:29
A std::set with AUI extensions.
Definition: ASet.h:25
static AStacktrace capture(unsigned skipFrames=0, unsigned maxFrames=128) noexcept
Creates stacktrace of the current thread.
Definition: AStacktraceImpl.cpp:156
Definition: IMatcher.h:18
Definition: UIMatcher.h:21
UIMatcher findNearestTo(UIMatcher matcher)
Finds the nearest view to the specified one.
Definition: UIMatcher.h:111
An std::weak_ptr with AUI extensions.
Definition: SharedPtrTypes.h:177
static _< T > fake(T *raw)
Definition: SharedPtrTypes.h:376