summaryrefslogtreecommitdiffstats
path: root/tests/manual/wasm/eventloop/suspendresumecontrol_auto/main.cpp
blob: ff3e67e3fc2e5c98caf3125cac04fff635d9b57a (plain)
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
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

#include <QtCore/qcoreapplication.h>
#include <QtCore/private/qwasmsuspendresumecontrol_p.h>
#include <QtCore/qdebug.h>
#include <qtwasmtestlib.h>

using namespace emscripten;

const std::chrono::milliseconds timerTimeout{10};

// Test QWasmSuspendResumeControl suspend/resume and event processing,
// via QWasmTimer native timer events.
class WasmSuspendResumeControlTest: public QObject
{
    Q_OBJECT
private slots:
    void timer();
    void multipleTimers();
    void reuseTimer();
    void cancelTimer();
    void deleteTimer();
    void suspendExclusive();
};

// Verify that a single timer fires
void WasmSuspendResumeControlTest::timer()
{
    QWasmSuspendResumeControl suspendResume;
    bool timerFired = false;

    QWasmTimer timer(&suspendResume, [&timerFired](){
        timerFired = true;
    });
    timer.setTimeout(timerTimeout);

    while (!timerFired) {
        suspendResume.suspend();
        suspendResume.sendPendingEvents();
    }

    QWASMSUCCESS();
}

// Verify that multiple parallel timers fire
void WasmSuspendResumeControlTest::multipleTimers()
{
    QWasmSuspendResumeControl suspendResume;
    const int expectedTimers = 10;
    int compledtedTimers = 0;

    std::unique_ptr<QWasmTimer> timers[expectedTimers];
    for (int i = 0; i < expectedTimers; ++i) {
        timers[i] = std::make_unique<QWasmTimer>(&suspendResume, [&compledtedTimers](){
            ++compledtedTimers;
        });
        timers[i]->setTimeout(timerTimeout * i);
    }

    while (compledtedTimers < expectedTimers) {
        suspendResume.suspend();
        suspendResume.sendPendingEvents();
    }

    QWASMSUCCESS();
}

// Verify that a reused timer fires again
void WasmSuspendResumeControlTest::reuseTimer()
{
    QWasmSuspendResumeControl suspendResume;
    const int expectedTimers = 10;
    int compledtedTimers = 0;

    QWasmTimer timer(&suspendResume, [&compledtedTimers](){
        ++compledtedTimers;
    });

    while (compledtedTimers < expectedTimers) {
        timer.setTimeout(timerTimeout);
        suspendResume.suspend();
        suspendResume.sendPendingEvents();
    }

    QWASMSUCCESS();
}

// Verify that a cancelled timer does not fire
void WasmSuspendResumeControlTest::cancelTimer()
{
    QWasmSuspendResumeControl suspendResume;

    // controlTimer checks that the cancelled testTimer didn't fire
    bool controlFired = false;
    QWasmTimer controlTimer(&suspendResume, [&controlFired](){
        controlFired = true;
    });

    QWasmTimer testTimer(&suspendResume, [](){
        QWASMFAIL("Cancelled timer did fire");
    });

    controlTimer.setTimeout(timerTimeout * 4);
    testTimer.setTimeout(timerTimeout);
    testTimer.clearTimeout();

    while (!controlFired) {
        suspendResume.suspend();
        suspendResume.sendPendingEvents();
    }

    QWASMSUCCESS();
}

// Verify that a deleted timer does not fire
void WasmSuspendResumeControlTest::deleteTimer()
{
    QWasmSuspendResumeControl suspendResume;

    // controlTimer checks that the deleted testTimer didn't fire
    bool controlFired = false;
    QWasmTimer controlTimer(&suspendResume, [&controlFired](){
        controlFired = true;
    });
    controlTimer.setTimeout(timerTimeout * 4);

    {
        QWasmTimer testTimer(&suspendResume, [](){
            QWASMFAIL("Deleted timer did fire");
        });
        testTimer.setTimeout(timerTimeout);
    }

    while (!controlFired) {
        suspendResume.suspend();
        suspendResume.sendPendingEvents();
    }

    QWASMSUCCESS();
}

// Verify that an exclusive suspend resumes for the exclusive event only
void WasmSuspendResumeControlTest::suspendExclusive()
{
    QWasmSuspendResumeControl suspendResume;

    // (re) implement a native timer - this gives us a unique event handler
    // index which we can suspend exclusively on.
    bool exclusiveTimerFired = false;
    auto exclusiveTimerHandler = [&exclusiveTimerFired](emscripten::val) {
        exclusiveTimerFired = true;
    };
    uint32_t exlusiveTimerHandlerIndex = suspendResume.registerEventHandler(std::move(exclusiveTimerHandler));

    std::chrono::milliseconds exclusiveTimerTimeout = timerTimeout * 4;
    double timoutValue = static_cast<double>(exclusiveTimerTimeout.count());
    val jsHandler = suspendResume.jsEventHandlerAt(exlusiveTimerHandlerIndex);
    val::global("window").call<double>("setTimeout", jsHandler, timoutValue);

    // Schedule suppressedTimer to fire before the exclusive timer. Expected
    // behavior is that it doesn't.
    bool suppressedTimerFired = false;
    QWasmTimer suppressedTimer(&suspendResume, [&suppressedTimerFired](){
        suppressedTimerFired = true;
    });
    suppressedTimer.setTimeout(timerTimeout);

    // Suspend exclusively for the exclusive timer, and verify that
    // the correct timers fired.
    suspendResume.suspendExclusive(exlusiveTimerHandlerIndex);
    suspendResume.sendPendingEvents(); // <- also clears exclusive mode
    if (!exclusiveTimerFired)
        QWASMFAIL("Exclusive timer did not fire");
    if (suppressedTimerFired)
        QWASMFAIL("Suppressed timer did fire");

    // Send (all) events, this should give is the suppressed timer
    suspendResume.sendPendingEvents();
    if (!suppressedTimerFired)
        QWASMFAIL("Suppressed timer did not fire");

    QWASMSUCCESS();
}

int main(int argc, char **argv)
{
    auto testObject = std::make_shared<WasmSuspendResumeControlTest>();
    QtWasmTest::initTestCase<QCoreApplication>(argc, argv, testObject);
    return 0;
}

#include "main.moc"