File: macro_saver.hpp

package info (click to toggle)
sight 25.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 42,184 kB
  • sloc: cpp: 289,476; xml: 17,257; ansic: 9,878; python: 1,379; sh: 144; makefile: 33
file content (373 lines) | stat: -rw-r--r-- 11,088 bytes parent folder | download | duplicates (3)
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
/************************************************************************
 *
 * Copyright (C) 2021-2024 IRCAD France
 *
 * This file is part of Sight.
 *
 * Sight is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Sight is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Sight. If not, see <https://www.gnu.org/licenses/>.
 *
 ***********************************************************************/
// cspell:ignore modif

#pragma once

#include <ui/test/helper/select.hpp>

#include <QEvent>
#include <QList>
#include <qnamespace.h>
#include <QObject>
#include <QPoint>
#include <QString>
#include <QVector>
#include <QWidget>

#include <cstdint>
#include <optional>

/// An enumeration which represents the type of a user interaction
enum interaction_t
{
    mouse_click,
    mouse_double_click,
    mouse_drag,
    mouse_wheel,
    keyboard_click,
    keyboard_sequence,
    model_view_select,
    number_input_modification,
    helper_api
};

/// An enumeration which represents how to find a widget, @see FindStrategy
enum class find_strategy_t
{
    root,                // The object to be found is root
    active_modal_widget, // The object to be found is the active modal widget
    object_name,         // Find an object using its object name
    global_type,         // Find an object using its type from the root
    action,              // Find an object via of its action, requires to find the action
    local_type,          // Find an object using its type from the parent, requires to find the parent
    nth_child,           // Find an object using its index in its parent children list, requires to find the parent
    cant_be_found        // Error: the object can't be found
};

enum class modification_t
{
    increment,
    decrement,
    set
};

/// A structure which represents a strategy to find a specific widget
struct find_strategy
{
    find_strategy_t type;
    QString class_name;
    QString string;
    int integer;
};

/// The base class for all interaction
struct macro_interaction
{
    macro_interaction(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers
    );

    intptr_t receiver_id;
    QVector<find_strategy> how_to_find_receiver;
    Qt::KeyboardModifiers modifiers;
};

/// An interaction before the preprocessing (that is, directly caught from Qt)
struct pre_interaction : public macro_interaction
{
    pre_interaction(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        QEvent::Type _type
    );

    QEvent::Type type;
};

/// An interaction after the preprocessing (ready to be translated into C++)
struct post_interaction : public macro_interaction
{
    post_interaction(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        interaction_t _type
    );

    interaction_t type;
};

/// A mouse interaction (mouse click, mouse drag...)
struct interaction_mouse
{
    interaction_mouse(QPoint _from, QPoint _to, Qt::MouseButton _button);

    QPoint from;
    QPoint to;
    Qt::MouseButton button;
};

/// A mouse wheel interaction
struct interaction_mouse_wheel
{
    interaction_mouse_wheel(QPoint _angle_delta, QPoint _pos);

    QPoint angle_delta;
    QPoint pos;
};

/// A keyboard interaction (key press, key sequence...)
struct interaction_keyboard
{
    interaction_keyboard(Qt::Key _key, QString _sequence);

    [[nodiscard]] bool is_printable() const;

    Qt::Key key;
    QString sequence;
};

/// An interaction when selecting an item on a model-based widget
struct interaction_model_view_select
{
    explicit interaction_model_view_select(QString _name);

    QString name;
};

struct number_input_modification
{
    explicit number_input_modification(modification_t _type, double _number);

    modification_t modif_type;
    double modif_number;
};

/// A mouse interaction before the preprocessing
struct pre_interaction_mouse : public pre_interaction,
                               public interaction_mouse
{
    pre_interaction_mouse(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        QEvent::Type _type,
        QPoint _from,
        QPoint _to,
        Qt::MouseButton _button
    );
};

/// A mouse wheel interaction before the preprocessing
struct pre_interaction_mouse_wheel : public pre_interaction,
                                     public interaction_mouse_wheel
{
    pre_interaction_mouse_wheel(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        QEvent::Type _type,
        QPoint _angle_delta,
        QPoint _pos
    );
};

/// A keyboard interaction before the preprocessing
struct pre_interaction_keyboard : public pre_interaction,
                                  public interaction_keyboard
{
    pre_interaction_keyboard(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        QEvent::Type _type,
        Qt::Key _key,
        const QString& _sequence
    );
};

/// A list widget click interaction before the preprocessing
struct pre_interaction_model_view_select : public pre_interaction,
                                           public interaction_model_view_select
{
    pre_interaction_model_view_select(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        QEvent::Type _type,
        const QString& _name
    );
};

struct pre_interaction_number_input_modification : public pre_interaction,
                                                   public number_input_modification
{
    pre_interaction_number_input_modification(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        QEvent::Type _type,
        modification_t _modif_type,
        double _modif_number
    );
};

/// A mouse interaction after the preprocessing
struct post_interaction_mouse : public post_interaction,
                                public interaction_mouse
{
    post_interaction_mouse(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        interaction_t _type,
        QPoint _from,
        QPoint _to,
        Qt::MouseButton _button
    );
};

/// A mouse wheel interaction after the preprocessing
struct post_interaction_mouse_wheel : public post_interaction,
                                      public interaction_mouse_wheel
{
    post_interaction_mouse_wheel(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        interaction_t _type,
        QPoint _angle_delta,
        QPoint _pos
    );
};

/// A keyboard interaction after the preprocessing
struct post_interaction_keyboard : public post_interaction,
                                   public interaction_keyboard
{
    post_interaction_keyboard(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        interaction_t _type,
        Qt::Key _key,
        const QString& _sequence
    );
};

/// A list widget click interaction after the preprocessing
struct post_interaction_model_view_select : public post_interaction,
                                            public interaction_model_view_select
{
    post_interaction_model_view_select(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        interaction_t _type,
        const QString& _name
    );
};

struct post_interaction_number_input_modification : public post_interaction,
                                                    public number_input_modification
{
    post_interaction_number_input_modification(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        Qt::KeyboardModifiers _modifiers,
        interaction_t _type,
        modification_t _modif_type,
        double _modif_number
    );
};

struct interaction_helper_api : public post_interaction
{
    interaction_helper_api(
        intptr_t _receiver_id,
        const QVector<find_strategy>& _how_to_find_receiver,
        QString _method_name,
        std::optional<sight::ui::test::helper::selector> _select,
        QStringList _args = {});

    QString method_name;
    std::optional<sight::ui::test::helper::selector> select;
    QStringList args;
};

/// Class which captures interactions to save them as a GuiTester-compatible GUI test C++ source file
class macro_saver : public QObject
{
Q_OBJECT

public:

    // Constructor. Does nothing.
    macro_saver() = default;

    /**
     * @brief Method used by Qt when an infected widget receives an event.
     * @details If it's the creation of a child widget, it infects it as well, if it's a user interaction, it saves it
     * in its interactions vector.
     *
     * @param _target The widget being targeted by the event
     * @param _e The event which was sent to the target
     * @returns Should the event handling stop?
     */
    bool eventFilter(QObject* _target, QEvent* _e) override;

    /**
     * @brief Infects a widget and its children recursively, so that the events they will receive will be filtered with
     * @ref MacroSaver
     *
     * @param _o The widget to infect
     */
    void infect(QObject* _o);

    /// Saves the user interactions as GuiTester-compatible GUI test C++ source files named GuiTest.cpp and GuiTest.hpp
    void save();

private:

    std::unique_ptr<pre_interaction> create_interaction(QObject* _target, QEvent* _e);
    QVector<find_strategy> find(QObject* _o);

    static QObject* findChild(
        QObject* _o,
        const QString& _type,
        const QString& _object_name   = "",
        Qt::FindChildOptions _options = Qt::FindChildrenRecursively
    );
    static QObjectList findChildren(
        QObject* _o,
        const QString& _type,
        const QString& _object_name   = "",
        Qt::FindChildOptions _options = Qt::FindChildrenRecursively
    );

    std::vector<std::unique_ptr<pre_interaction> > m_interactions;
    QWidget* m_main_window  = nullptr;
    bool m_drag_in_progress = false;
};