mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-05 00:35:27 +08:00
qt 6.5.1 original
This commit is contained in:
72
tests/manual/wasm/qstdweb/CMakeLists.txt
Normal file
72
tests/manual/wasm/qstdweb/CMakeLists.txt
Normal file
@ -0,0 +1,72 @@
|
||||
qt_internal_add_manual_test(promise_auto
|
||||
SOURCES
|
||||
promise_main.cpp
|
||||
../qtwasmtestlib/qtwasmtestlib.cpp
|
||||
LIBRARIES
|
||||
Qt::Core
|
||||
Qt::CorePrivate
|
||||
)
|
||||
|
||||
include_directories(../qtwasmtestlib/)
|
||||
|
||||
add_custom_command(
|
||||
TARGET promise_auto POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/promise_auto.html
|
||||
${CMAKE_CURRENT_BINARY_DIR}/promise_auto.html)
|
||||
|
||||
add_custom_command(
|
||||
TARGET promise_auto POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../qtwasmtestlib/qtwasmtestlib.js
|
||||
${CMAKE_CURRENT_BINARY_DIR}/qtwasmtestlib.js)
|
||||
|
||||
qt_internal_add_manual_test(files_auto
|
||||
SOURCES
|
||||
files_main.cpp
|
||||
../qtwasmtestlib/qtwasmtestlib.cpp
|
||||
LIBRARIES
|
||||
Qt::Core
|
||||
Qt::CorePrivate
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
|
||||
include_directories(../qtwasmtestlib/)
|
||||
|
||||
add_custom_command(
|
||||
TARGET files_auto POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/files_auto.html
|
||||
${CMAKE_CURRENT_BINARY_DIR}/files_auto.html)
|
||||
|
||||
add_custom_command(
|
||||
TARGET files_auto POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../qtwasmtestlib/qtwasmtestlib.js
|
||||
${CMAKE_CURRENT_BINARY_DIR}/qtwasmtestlib.js)
|
||||
|
||||
qt_internal_add_manual_test(qwasmcompositor_auto
|
||||
SOURCES
|
||||
qwasmcompositor_main.cpp
|
||||
../qtwasmtestlib/qtwasmtestlib.cpp
|
||||
LIBRARIES
|
||||
Qt::Core
|
||||
Qt::CorePrivate
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
|
||||
include_directories(../qtwasmtestlib/)
|
||||
|
||||
add_custom_command(
|
||||
TARGET qwasmcompositor_auto POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qwasmcompositor_auto.html
|
||||
${CMAKE_CURRENT_BINARY_DIR}/qwasmcompositor_auto.html)
|
||||
|
||||
add_custom_command(
|
||||
TARGET qwasmcompositor_auto POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../qtwasmtestlib/qtwasmtestlib.js
|
||||
${CMAKE_CURRENT_BINARY_DIR}/qtwasmtestlib.js)
|
||||
|
||||
target_link_options(qwasmcompositor_auto PRIVATE -sASYNCIFY -Os)
|
13
tests/manual/wasm/qstdweb/files_auto.html
Normal file
13
tests/manual/wasm/qstdweb/files_auto.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<script type="text/javascript" src="https://sinonjs.org/releases/sinon-14.0.0.js"
|
||||
integrity="sha384-z8J4N1s2hPDn6ClmFXDQkKD/e738VOWcR8JmhztPRa+PgezxQupgZu3LzoBO4Jw8"
|
||||
crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="qtwasmtestlib.js"></script>
|
||||
<script type="text/javascript" src="files_auto.js"></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
runTestCase(document.getElementById("log"));
|
||||
};
|
||||
</script>
|
||||
<p>Running files auto test.</p>
|
||||
<div id="log"></div>
|
471
tests/manual/wasm/qstdweb/files_main.cpp
Normal file
471
tests/manual/wasm/qstdweb/files_main.cpp
Normal file
@ -0,0 +1,471 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QEvent>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtGui/private/qwasmlocalfileaccess_p.h>
|
||||
|
||||
#include <qtwasmtestlib.h>
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/bind.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
class FilesTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FilesTest() : m_window(val::global("window")), m_testSupport(val::object()) {}
|
||||
|
||||
~FilesTest() noexcept {
|
||||
for (auto& cleanup: m_cleanup) {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void init() {
|
||||
EM_ASM({
|
||||
window.testSupport = {};
|
||||
|
||||
window.showOpenFilePicker = sinon.stub();
|
||||
|
||||
window.mockOpenFileDialog = (files) => {
|
||||
window.showOpenFilePicker.withArgs(sinon.match.any).callsFake(
|
||||
(options) => Promise.resolve(files.map(file => {
|
||||
const getFile = sinon.stub();
|
||||
getFile.callsFake(() => Promise.resolve({
|
||||
name: file.name,
|
||||
size: file.content.length,
|
||||
slice: () => new Blob([new TextEncoder().encode(file.content)]),
|
||||
}));
|
||||
return {
|
||||
kind: 'file',
|
||||
name: file.name,
|
||||
getFile
|
||||
};
|
||||
}))
|
||||
);
|
||||
};
|
||||
|
||||
window.showSaveFilePicker = sinon.stub();
|
||||
|
||||
window.mockSaveFilePicker = (file) => {
|
||||
window.showSaveFilePicker.withArgs(sinon.match.any).callsFake(
|
||||
(options) => {
|
||||
const createWritable = sinon.stub();
|
||||
createWritable.callsFake(() => {
|
||||
const write = file.writeFn ?? (() => {
|
||||
const write = sinon.stub();
|
||||
write.callsFake((stuff) => {
|
||||
if (file.content !== new TextDecoder().decode(stuff)) {
|
||||
const message = `Bad file content ${file.content} !== ${new TextDecoder().decode(stuff)}`;
|
||||
Module.qtWasmFail(message);
|
||||
return Promise.reject(message);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
});
|
||||
return write;
|
||||
})();
|
||||
|
||||
window.testSupport.write = write;
|
||||
|
||||
const close = file.closeFn ?? (() => {
|
||||
const close = sinon.stub();
|
||||
close.callsFake(() => Promise.resolve());
|
||||
return close;
|
||||
})();
|
||||
|
||||
window.testSupport.close = close;
|
||||
|
||||
return Promise.resolve({
|
||||
write,
|
||||
close
|
||||
});
|
||||
});
|
||||
return Promise.resolve({
|
||||
kind: 'file',
|
||||
name: file.name,
|
||||
createWritable
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T* Own(T* plainPtr) {
|
||||
m_cleanup.emplace_back([plainPtr]() mutable {
|
||||
delete plainPtr;
|
||||
});
|
||||
return plainPtr;
|
||||
}
|
||||
|
||||
val m_window;
|
||||
val m_testSupport;
|
||||
|
||||
std::vector<std::function<void()>> m_cleanup;
|
||||
|
||||
private slots:
|
||||
void selectOneFileWithFileDialog();
|
||||
void selectMultipleFilesWithFileDialog();
|
||||
void cancelFileDialog();
|
||||
void rejectFile();
|
||||
void saveFileWithFileDialog();
|
||||
};
|
||||
|
||||
class BarrierCallback {
|
||||
public:
|
||||
BarrierCallback(int number, std::function<void()> onDone)
|
||||
: m_remaining(number), m_onDone(std::move(onDone)) {}
|
||||
|
||||
void operator()() {
|
||||
if (!--m_remaining) {
|
||||
m_onDone();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int m_remaining;
|
||||
std::function<void()> m_onDone;
|
||||
};
|
||||
|
||||
|
||||
template <class Arg>
|
||||
std::string argToString(std::add_lvalue_reference_t<std::add_const_t<Arg>> arg) {
|
||||
return std::to_string(arg);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string argToString<bool>(const bool& value) {
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string argToString<std::string>(const std::string& arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string argToString<const std::string&>(const std::string& arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
struct Matcher {
|
||||
virtual ~Matcher() = default;
|
||||
|
||||
virtual bool matches(std::string* explanation, const Type& actual) const = 0;
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
struct AnyMatcher : public Matcher<Type> {
|
||||
bool matches(std::string* explanation, const Type& actual) const final {
|
||||
Q_UNUSED(explanation);
|
||||
Q_UNUSED(actual);
|
||||
return true;
|
||||
}
|
||||
|
||||
Type m_value;
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
struct EqualsMatcher : public Matcher<Type> {
|
||||
EqualsMatcher(Type value) : m_value(std::forward<Type>(value)) {}
|
||||
|
||||
bool matches(std::string* explanation, const Type& actual) const final {
|
||||
const bool ret = actual == m_value;
|
||||
if (!ret)
|
||||
*explanation += argToString<Type>(actual) + " != " + argToString<Type>(m_value);
|
||||
return actual == m_value;
|
||||
}
|
||||
|
||||
// It is crucial to hold a copy, otherwise we lose const refs.
|
||||
std::remove_reference_t<Type> m_value;
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
std::unique_ptr<EqualsMatcher<Type>> equals(Type value) {
|
||||
return std::make_unique<EqualsMatcher<Type>>(value);
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
std::unique_ptr<AnyMatcher<Type>> any(Type value) {
|
||||
return std::make_unique<AnyMatcher<Type>>(value);
|
||||
}
|
||||
|
||||
template <class ...Types>
|
||||
struct Expectation {
|
||||
std::tuple<std::unique_ptr<Matcher<Types>>...> m_argMatchers;
|
||||
int m_callCount = 0;
|
||||
int m_expectedCalls = 1;
|
||||
|
||||
template<std::size_t... Indices>
|
||||
bool match(std::string* explanation, const std::tuple<Types...>& tuple, std::index_sequence<Indices...>) const {
|
||||
return ( ... && (std::get<Indices>(m_argMatchers)->matches(explanation, std::get<Indices>(tuple))));
|
||||
}
|
||||
|
||||
bool matches(std::string* explanation, Types... args) const {
|
||||
if (m_callCount >= m_expectedCalls) {
|
||||
*explanation += "Too many calls\n";
|
||||
return false;
|
||||
}
|
||||
return match(explanation, std::make_tuple(args...), std::make_index_sequence<std::tuple_size_v<std::tuple<Types...>>>());
|
||||
}
|
||||
};
|
||||
|
||||
template <class R, class ...Types>
|
||||
struct Behavior {
|
||||
std::function<R(Types...)> m_callback;
|
||||
|
||||
void call(std::function<R(Types...)> callback) {
|
||||
m_callback = std::move(callback);
|
||||
}
|
||||
};
|
||||
|
||||
template<class... Args>
|
||||
std::string argsToString(Args... args) {
|
||||
return (... + (", " + argToString<Args>(args)));
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string argsToString<>() {
|
||||
return "";
|
||||
}
|
||||
|
||||
template<class R, class ...Types>
|
||||
struct ExpectationToBehaviorMapping {
|
||||
Expectation<Types...> expectation;
|
||||
Behavior<R, Types...> behavior;
|
||||
};
|
||||
|
||||
template<class R, class... Args>
|
||||
class MockCallback {
|
||||
public:
|
||||
std::function<R(Args...)> get() {
|
||||
return [this](Args... result) -> R {
|
||||
return processCall(std::forward<Args>(result)...);
|
||||
};
|
||||
}
|
||||
|
||||
Behavior<R, Args...>& expectCallWith(std::unique_ptr<Matcher<Args>>... matcherArgs) {
|
||||
auto matchers = std::make_tuple(std::move(matcherArgs)...);
|
||||
m_behaviorByExpectation.push_back({Expectation<Args...> {std::move(matchers)}, Behavior<R, Args...> {}});
|
||||
return m_behaviorByExpectation.back().behavior;
|
||||
}
|
||||
|
||||
Behavior<R, Args...>& expectRepeatedCallWith(int times, std::unique_ptr<Matcher<Args>>... matcherArgs) {
|
||||
auto matchers = std::make_tuple(std::move(matcherArgs)...);
|
||||
m_behaviorByExpectation.push_back({Expectation<Args...> {std::move(matchers), 0, times}, Behavior<R, Args...> {}});
|
||||
return m_behaviorByExpectation.back().behavior;
|
||||
}
|
||||
|
||||
private:
|
||||
R processCall(Args... args) {
|
||||
std::string argsAsString = argsToString(args...);
|
||||
std::string triedExpectations;
|
||||
auto it = std::find_if(m_behaviorByExpectation.begin(), m_behaviorByExpectation.end(),
|
||||
[&](const ExpectationToBehaviorMapping<R, Args...>& behavior) {
|
||||
return behavior.expectation.matches(&triedExpectations, std::forward<Args>(args)...);
|
||||
});
|
||||
if (it != m_behaviorByExpectation.end()) {
|
||||
++it->expectation.m_callCount;
|
||||
return it->behavior.m_callback(args...);
|
||||
} else {
|
||||
QWASMFAIL("Unexpected call with " + argsAsString + ". Tried: " + triedExpectations);
|
||||
}
|
||||
return R();
|
||||
}
|
||||
|
||||
std::vector<ExpectationToBehaviorMapping<R, Args...>> m_behaviorByExpectation;
|
||||
};
|
||||
|
||||
void FilesTest::selectOneFileWithFileDialog()
|
||||
{
|
||||
init();
|
||||
|
||||
static constexpr std::string_view testFileContent = "This is a happy case.";
|
||||
|
||||
EM_ASM({
|
||||
mockOpenFileDialog([{
|
||||
name: 'file1.jpg',
|
||||
content: UTF8ToString($0)
|
||||
}]);
|
||||
}, testFileContent.data());
|
||||
|
||||
auto* fileSelectedCallback = Own(new MockCallback<void, bool>());
|
||||
fileSelectedCallback->expectCallWith(equals(true)).call([](bool) mutable {});
|
||||
|
||||
auto* fileBuffer = Own(new QByteArray());
|
||||
|
||||
auto* acceptFileCallback = Own(new MockCallback<char*, uint64_t, const std::string&>());
|
||||
acceptFileCallback->expectCallWith(equals<uint64_t>(testFileContent.size()), equals<const std::string&>("file1.jpg"))
|
||||
.call([fileBuffer](uint64_t, std::string) mutable -> char* {
|
||||
fileBuffer->resize(testFileContent.size());
|
||||
return fileBuffer->data();
|
||||
});
|
||||
|
||||
auto* fileDataReadyCallback = Own(new MockCallback<void>());
|
||||
fileDataReadyCallback->expectCallWith().call([fileBuffer]() mutable {
|
||||
QWASMCOMPARE(fileBuffer->data(), std::string(testFileContent));
|
||||
QWASMSUCCESS();
|
||||
});
|
||||
|
||||
QWasmLocalFileAccess::openFile(
|
||||
{QStringLiteral("*")}, fileSelectedCallback->get(), acceptFileCallback->get(), fileDataReadyCallback->get());
|
||||
}
|
||||
|
||||
void FilesTest::selectMultipleFilesWithFileDialog()
|
||||
{
|
||||
static constexpr std::array<std::string_view, 3> testFileContent =
|
||||
{ "Cont 1", "2s content", "What is hiding in 3?"};
|
||||
|
||||
init();
|
||||
|
||||
EM_ASM({
|
||||
mockOpenFileDialog([{
|
||||
name: 'file1.jpg',
|
||||
content: UTF8ToString($0)
|
||||
}, {
|
||||
name: 'file2.jpg',
|
||||
content: UTF8ToString($1)
|
||||
}, {
|
||||
name: 'file3.jpg',
|
||||
content: UTF8ToString($2)
|
||||
}]);
|
||||
}, testFileContent[0].data(), testFileContent[1].data(), testFileContent[2].data());
|
||||
|
||||
auto* fileSelectedCallback = Own(new MockCallback<void, int>());
|
||||
fileSelectedCallback->expectCallWith(equals(3)).call([](int) mutable {});
|
||||
|
||||
auto fileBuffer = std::make_shared<QByteArray>();
|
||||
|
||||
auto* acceptFileCallback = Own(new MockCallback<char*, uint64_t, const std::string&>());
|
||||
acceptFileCallback->expectCallWith(equals<uint64_t>(testFileContent[0].size()), equals<const std::string&>("file1.jpg"))
|
||||
.call([fileBuffer](uint64_t, std::string) mutable -> char* {
|
||||
fileBuffer->resize(testFileContent[0].size());
|
||||
return fileBuffer->data();
|
||||
});
|
||||
acceptFileCallback->expectCallWith(equals<uint64_t>(testFileContent[1].size()), equals<const std::string&>("file2.jpg"))
|
||||
.call([fileBuffer](uint64_t, std::string) mutable -> char* {
|
||||
fileBuffer->resize(testFileContent[1].size());
|
||||
return fileBuffer->data();
|
||||
});
|
||||
acceptFileCallback->expectCallWith(equals<uint64_t>(testFileContent[2].size()), equals<const std::string&>("file3.jpg"))
|
||||
.call([fileBuffer](uint64_t, std::string) mutable -> char* {
|
||||
fileBuffer->resize(testFileContent[2].size());
|
||||
return fileBuffer->data();
|
||||
});
|
||||
|
||||
auto* fileDataReadyCallback = Own(new MockCallback<void>());
|
||||
fileDataReadyCallback->expectRepeatedCallWith(3).call([fileBuffer]() mutable {
|
||||
static int callCount = 0;
|
||||
QWASMCOMPARE(fileBuffer->data(), std::string(testFileContent[callCount]));
|
||||
|
||||
callCount++;
|
||||
if (callCount == 3) {
|
||||
QWASMSUCCESS();
|
||||
}
|
||||
});
|
||||
|
||||
QWasmLocalFileAccess::openFiles(
|
||||
{QStringLiteral("*")}, QWasmLocalFileAccess::FileSelectMode::MultipleFiles,
|
||||
fileSelectedCallback->get(), acceptFileCallback->get(), fileDataReadyCallback->get());
|
||||
}
|
||||
|
||||
void FilesTest::cancelFileDialog()
|
||||
{
|
||||
init();
|
||||
|
||||
EM_ASM({
|
||||
window.showOpenFilePicker.withArgs(sinon.match.any).returns(Promise.reject("The user cancelled the dialog"));
|
||||
});
|
||||
|
||||
auto* fileSelectedCallback = Own(new MockCallback<void, bool>());
|
||||
fileSelectedCallback->expectCallWith(equals(false)).call([](bool) mutable {
|
||||
QWASMSUCCESS();
|
||||
});
|
||||
|
||||
auto* acceptFileCallback = Own(new MockCallback<char*, uint64_t, const std::string&>());
|
||||
auto* fileDataReadyCallback = Own(new MockCallback<void>());
|
||||
|
||||
QWasmLocalFileAccess::openFile(
|
||||
{QStringLiteral("*")}, fileSelectedCallback->get(), acceptFileCallback->get(), fileDataReadyCallback->get());
|
||||
}
|
||||
|
||||
void FilesTest::rejectFile()
|
||||
{
|
||||
init();
|
||||
|
||||
static constexpr std::string_view testFileContent = "We don't want this file.";
|
||||
|
||||
EM_ASM({
|
||||
mockOpenFileDialog([{
|
||||
name: 'dontwant.dat',
|
||||
content: UTF8ToString($0)
|
||||
}]);
|
||||
}, testFileContent.data());
|
||||
|
||||
auto* fileSelectedCallback = Own(new MockCallback<void, bool>());
|
||||
fileSelectedCallback->expectCallWith(equals(true)).call([](bool) mutable {});
|
||||
|
||||
auto* fileDataReadyCallback = Own(new MockCallback<void>());
|
||||
|
||||
auto* acceptFileCallback = Own(new MockCallback<char*, uint64_t, const std::string&>());
|
||||
acceptFileCallback->expectCallWith(equals<uint64_t>(std::string_view(testFileContent).size()), equals<const std::string&>("dontwant.dat"))
|
||||
.call([](uint64_t, const std::string) {
|
||||
QTimer::singleShot(0, []() {
|
||||
// No calls to fileDataReadyCallback
|
||||
QWASMSUCCESS();
|
||||
});
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
QWasmLocalFileAccess::openFile(
|
||||
{QStringLiteral("*")}, fileSelectedCallback->get(), acceptFileCallback->get(), fileDataReadyCallback->get());
|
||||
}
|
||||
|
||||
void FilesTest::saveFileWithFileDialog()
|
||||
{
|
||||
init();
|
||||
|
||||
static constexpr std::string_view testFileContent = "Save this important content";
|
||||
|
||||
EM_ASM({
|
||||
mockSaveFilePicker({
|
||||
name: 'somename',
|
||||
content: UTF8ToString($0),
|
||||
closeFn: (() => {
|
||||
const close = sinon.stub();
|
||||
close.callsFake(() =>
|
||||
new Promise(resolve => {
|
||||
resolve();
|
||||
Module.qtWasmPass();
|
||||
}));
|
||||
return close;
|
||||
})()
|
||||
});
|
||||
}, testFileContent.data());
|
||||
|
||||
QByteArray data;
|
||||
data.prepend(testFileContent);
|
||||
QWasmLocalFileAccess::saveFile(data, "hintie");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
auto testObject = std::make_shared<FilesTest>();
|
||||
QtWasmTest::initTestCase<QCoreApplication>(argc, argv, testObject);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "files_main.moc"
|
10
tests/manual/wasm/qstdweb/promise_auto.html
Normal file
10
tests/manual/wasm/qstdweb/promise_auto.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!doctype html>
|
||||
<script type="text/javascript" src="qtwasmtestlib.js"></script>
|
||||
<script type="text/javascript" src="promise_auto.js"></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
runTestCase(document.getElementById("log"));
|
||||
};
|
||||
</script>
|
||||
<p>Running promise auto test.</p>
|
||||
<div id="log"></div>
|
486
tests/manual/wasm/qstdweb/promise_main.cpp
Normal file
486
tests/manual/wasm/qstdweb/promise_main.cpp
Normal file
@ -0,0 +1,486 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QEvent>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/private/qstdweb_p.h>
|
||||
|
||||
#include <qtwasmtestlib.h>
|
||||
#include <emscripten.h>
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
class WasmPromiseTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WasmPromiseTest() : m_window(val::global("window")), m_testSupport(val::object()) {}
|
||||
|
||||
~WasmPromiseTest() noexcept = default;
|
||||
|
||||
private:
|
||||
void init() {
|
||||
m_testSupport = val::object();
|
||||
m_window.set("testSupport", m_testSupport);
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve = {};
|
||||
testSupport.reject = {};
|
||||
testSupport.promises = {};
|
||||
testSupport.waitConditionPromise = new Promise((resolve, reject) => {
|
||||
testSupport.finishWaiting = resolve;
|
||||
});
|
||||
|
||||
testSupport.makeTestPromise = (param) => {
|
||||
testSupport.promises[param] = new Promise((resolve, reject) => {
|
||||
testSupport.resolve[param] = resolve;
|
||||
testSupport.reject[param] = reject;
|
||||
});
|
||||
|
||||
return testSupport.promises[param];
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
val m_window;
|
||||
val m_testSupport;
|
||||
|
||||
private slots:
|
||||
void simpleResolve();
|
||||
void multipleResolve();
|
||||
void simpleReject();
|
||||
void multipleReject();
|
||||
void throwInThen();
|
||||
void bareFinally();
|
||||
void finallyWithThen();
|
||||
void finallyWithThrow();
|
||||
void finallyWithThrowInThen();
|
||||
void nested();
|
||||
void all();
|
||||
void allWithThrow();
|
||||
void allWithFinally();
|
||||
void allWithFinallyAndThrow();
|
||||
};
|
||||
|
||||
class BarrierCallback {
|
||||
public:
|
||||
BarrierCallback(int number, std::function<void()> onDone)
|
||||
: m_remaining(number), m_onDone(std::move(onDone)) {}
|
||||
|
||||
void operator()() {
|
||||
if (!--m_remaining) {
|
||||
m_onDone();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int m_remaining;
|
||||
std::function<void()> m_onDone;
|
||||
};
|
||||
|
||||
// Post event to the main thread and verify that it is processed.
|
||||
void WasmPromiseTest::simpleResolve()
|
||||
{
|
||||
init();
|
||||
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.thenFunc = [](val result) {
|
||||
QWASMVERIFY(result.isString());
|
||||
QWASMCOMPARE("Some lovely data", result.as<std::string>());
|
||||
|
||||
QWASMSUCCESS();
|
||||
},
|
||||
.catchFunc = [](val error) {
|
||||
Q_UNUSED(error);
|
||||
|
||||
QWASMFAIL("Unexpected catch");
|
||||
}
|
||||
}, std::string("simpleResolve"));
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["simpleResolve"]("Some lovely data");
|
||||
});
|
||||
}
|
||||
|
||||
void WasmPromiseTest::multipleResolve()
|
||||
{
|
||||
init();
|
||||
|
||||
static constexpr int promiseCount = 1000;
|
||||
|
||||
auto onThen = std::make_shared<BarrierCallback>(promiseCount, []() {
|
||||
QWASMSUCCESS();
|
||||
});
|
||||
|
||||
for (int i = 0; i < promiseCount; ++i) {
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.thenFunc = [=](val result) {
|
||||
QWASMVERIFY(result.isString());
|
||||
QWASMCOMPARE(QString::number(i).toStdString(), result.as<std::string>());
|
||||
|
||||
(*onThen)();
|
||||
},
|
||||
.catchFunc = [](val error) {
|
||||
Q_UNUSED(error);
|
||||
QWASMFAIL("Unexpected catch");
|
||||
}
|
||||
}, (QStringLiteral("test") + QString::number(i)).toStdString());
|
||||
}
|
||||
|
||||
EM_ASM({
|
||||
for (let i = $0 - 1; i >= 0; --i) {
|
||||
testSupport.resolve['test' + i](`${i}`);
|
||||
}
|
||||
}, promiseCount);
|
||||
}
|
||||
|
||||
void WasmPromiseTest::simpleReject()
|
||||
{
|
||||
init();
|
||||
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.thenFunc = [](val result) {
|
||||
Q_UNUSED(result);
|
||||
QWASMFAIL("Unexpected then");
|
||||
},
|
||||
.catchFunc = [](val result) {
|
||||
QWASMVERIFY(result.isString());
|
||||
QWASMCOMPARE("Evil error", result.as<std::string>());
|
||||
QWASMSUCCESS();
|
||||
}
|
||||
}, std::string("simpleReject"));
|
||||
|
||||
EM_ASM({
|
||||
testSupport.reject["simpleReject"]("Evil error");
|
||||
});
|
||||
}
|
||||
|
||||
void WasmPromiseTest::multipleReject()
|
||||
{
|
||||
static constexpr int promiseCount = 1000;
|
||||
|
||||
auto onCatch = std::make_shared<BarrierCallback>(promiseCount, []() {
|
||||
QWASMSUCCESS();
|
||||
});
|
||||
|
||||
for (int i = 0; i < promiseCount; ++i) {
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.thenFunc = [=](val result) {
|
||||
QWASMVERIFY(result.isString());
|
||||
QWASMCOMPARE(QString::number(i).toStdString(), result.as<std::string>());
|
||||
|
||||
(*onCatch)();
|
||||
},
|
||||
.catchFunc = [](val error) {
|
||||
Q_UNUSED(error);
|
||||
QWASMFAIL("Unexpected catch");
|
||||
}
|
||||
}, (QStringLiteral("test") + QString::number(i)).toStdString());
|
||||
}
|
||||
|
||||
EM_ASM({
|
||||
for (let i = $0 - 1; i >= 0; --i) {
|
||||
testSupport.resolve['test' + i](`${i}`);
|
||||
}
|
||||
}, promiseCount);
|
||||
}
|
||||
|
||||
void WasmPromiseTest::throwInThen()
|
||||
{
|
||||
init();
|
||||
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.thenFunc = [](val result) {
|
||||
Q_UNUSED(result);
|
||||
EM_ASM({
|
||||
throw "Expected error";
|
||||
});
|
||||
},
|
||||
.catchFunc = [](val error) {
|
||||
QWASMCOMPARE("Expected error", error.as<std::string>());
|
||||
QWASMSUCCESS();
|
||||
}
|
||||
}, std::string("throwInThen"));
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["throwInThen"]();
|
||||
});
|
||||
}
|
||||
|
||||
void WasmPromiseTest::bareFinally()
|
||||
{
|
||||
init();
|
||||
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.finallyFunc = []() {
|
||||
QWASMSUCCESS();
|
||||
}
|
||||
}, std::string("bareFinally"));
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["bareFinally"]();
|
||||
});
|
||||
}
|
||||
|
||||
void WasmPromiseTest::finallyWithThen()
|
||||
{
|
||||
init();
|
||||
|
||||
auto thenCalled = std::make_shared<bool>();
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.thenFunc = [thenCalled] (val result) {
|
||||
Q_UNUSED(result);
|
||||
*thenCalled = true;
|
||||
},
|
||||
.finallyFunc = [thenCalled]() {
|
||||
QWASMVERIFY(*thenCalled);
|
||||
QWASMSUCCESS();
|
||||
}
|
||||
}, std::string("finallyWithThen"));
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["finallyWithThen"]();
|
||||
});
|
||||
}
|
||||
|
||||
void WasmPromiseTest::finallyWithThrow()
|
||||
{
|
||||
init();
|
||||
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.catchFunc = [](val error) {
|
||||
Q_UNUSED(error);
|
||||
},
|
||||
.finallyFunc = []() {
|
||||
QWASMSUCCESS();
|
||||
}
|
||||
}, std::string("finallyWithThrow"));
|
||||
|
||||
EM_ASM({
|
||||
testSupport.reject["finallyWithThrow"]();
|
||||
});
|
||||
}
|
||||
|
||||
void WasmPromiseTest::finallyWithThrowInThen()
|
||||
{
|
||||
init();
|
||||
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.thenFunc = [](val result) {
|
||||
Q_UNUSED(result);
|
||||
EM_ASM({
|
||||
throw "Expected error";
|
||||
});
|
||||
},
|
||||
.catchFunc = [](val result) {
|
||||
QWASMVERIFY(result.isString());
|
||||
QWASMCOMPARE("Expected error", result.as<std::string>());
|
||||
},
|
||||
.finallyFunc = []() {
|
||||
QWASMSUCCESS();
|
||||
}
|
||||
}, std::string("bareFinallyWithThen"));
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["bareFinallyWithThen"]();
|
||||
});
|
||||
}
|
||||
|
||||
void WasmPromiseTest::nested()
|
||||
{
|
||||
init();
|
||||
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.thenFunc = [this](val result) {
|
||||
QWASMVERIFY(result.isString());
|
||||
QWASMCOMPARE("Outer data", result.as<std::string>());
|
||||
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.thenFunc = [this](val innerResult) {
|
||||
QWASMVERIFY(innerResult.isString());
|
||||
QWASMCOMPARE("Inner data", innerResult.as<std::string>());
|
||||
|
||||
qstdweb::Promise::make(m_testSupport, "makeTestPromise", {
|
||||
.thenFunc = [](val innerResult) {
|
||||
QWASMVERIFY(innerResult.isString());
|
||||
QWASMCOMPARE("Innermost data", innerResult.as<std::string>());
|
||||
|
||||
QWASMSUCCESS();
|
||||
},
|
||||
.catchFunc = [](val error) {
|
||||
Q_UNUSED(error);
|
||||
QWASMFAIL("Unexpected catch");
|
||||
}
|
||||
}, std::string("innermost"));
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["innermost"]("Innermost data");
|
||||
});
|
||||
},
|
||||
.catchFunc = [](val error) {
|
||||
Q_UNUSED(error);
|
||||
QWASMFAIL("Unexpected catch");
|
||||
}
|
||||
}, std::string("inner"));
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["inner"]("Inner data");
|
||||
});
|
||||
},
|
||||
.catchFunc = [](val error) {
|
||||
Q_UNUSED(error);
|
||||
QWASMFAIL("Unexpected catch");
|
||||
}
|
||||
}, std::string("outer"));
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["outer"]("Outer data");
|
||||
});
|
||||
}
|
||||
|
||||
void WasmPromiseTest::all()
|
||||
{
|
||||
init();
|
||||
|
||||
static constexpr int promiseCount = 1000;
|
||||
auto thenCalledOnce = std::shared_ptr<bool>();
|
||||
*thenCalledOnce = true;
|
||||
|
||||
std::vector<val> promises;
|
||||
promises.reserve(promiseCount);
|
||||
|
||||
for (int i = 0; i < promiseCount; ++i) {
|
||||
promises.push_back(m_testSupport.call<val>("makeTestPromise", val(("all" + QString::number(i)).toStdString())));
|
||||
}
|
||||
|
||||
qstdweb::Promise::all(std::move(promises), {
|
||||
.thenFunc = [=](val result) {
|
||||
QWASMVERIFY(*thenCalledOnce);
|
||||
*thenCalledOnce = false;
|
||||
|
||||
QWASMVERIFY(result.isArray());
|
||||
QWASMCOMPARE(promiseCount, result["length"].as<int>());
|
||||
for (int i = 0; i < promiseCount; ++i) {
|
||||
QWASMCOMPARE(QStringLiteral("Data %1").arg(i).toStdString(), result[i].as<std::string>());
|
||||
}
|
||||
|
||||
QWASMSUCCESS();
|
||||
},
|
||||
.catchFunc = [](val error) {
|
||||
Q_UNUSED(error);
|
||||
QWASMFAIL("Unexpected catch");
|
||||
}
|
||||
});
|
||||
|
||||
EM_ASM({
|
||||
console.log('Resolving');
|
||||
for (let i = $0 - 1; i >= 0; --i) {
|
||||
testSupport.resolve['all' + i](`Data ${i}`);
|
||||
}
|
||||
}, promiseCount);
|
||||
}
|
||||
|
||||
void WasmPromiseTest::allWithThrow()
|
||||
{
|
||||
init();
|
||||
|
||||
val promise1 = m_testSupport.call<val>("makeTestPromise", val("promise1"));
|
||||
val promise2 = m_testSupport.call<val>("makeTestPromise", val("promise2"));
|
||||
val promise3 = m_testSupport.call<val>("makeTestPromise", val("promise3"));
|
||||
|
||||
auto catchCalledOnce = std::shared_ptr<bool>();
|
||||
*catchCalledOnce = true;
|
||||
|
||||
qstdweb::Promise::all({promise1, promise2, promise3}, {
|
||||
.thenFunc = [](val result) {
|
||||
Q_UNUSED(result);
|
||||
QWASMFAIL("Unexpected then");
|
||||
},
|
||||
.catchFunc = [catchCalledOnce](val result) {
|
||||
QWASMVERIFY(*catchCalledOnce);
|
||||
*catchCalledOnce = false;
|
||||
QWASMVERIFY(result.isString());
|
||||
QWASMCOMPARE("Error 2", result.as<std::string>());
|
||||
QWASMSUCCESS();
|
||||
}
|
||||
});
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["promise3"]("Data 3");
|
||||
testSupport.resolve["promise1"]("Data 1");
|
||||
testSupport.reject["promise2"]("Error 2");
|
||||
});
|
||||
}
|
||||
|
||||
void WasmPromiseTest::allWithFinally()
|
||||
{
|
||||
init();
|
||||
|
||||
val promise1 = m_testSupport.call<val>("makeTestPromise", val("promise1"));
|
||||
val promise2 = m_testSupport.call<val>("makeTestPromise", val("promise2"));
|
||||
val promise3 = m_testSupport.call<val>("makeTestPromise", val("promise3"));
|
||||
|
||||
auto finallyCalledOnce = std::shared_ptr<bool>();
|
||||
*finallyCalledOnce = true;
|
||||
|
||||
qstdweb::Promise::all({promise1, promise2, promise3}, {
|
||||
.thenFunc = [](val result) {
|
||||
Q_UNUSED(result);
|
||||
},
|
||||
.finallyFunc = [finallyCalledOnce]() {
|
||||
QWASMVERIFY(*finallyCalledOnce);
|
||||
*finallyCalledOnce = false;
|
||||
QWASMSUCCESS();
|
||||
}
|
||||
});
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["promise3"]("Data 3");
|
||||
testSupport.resolve["promise1"]("Data 1");
|
||||
testSupport.resolve["promise2"]("Data 2");
|
||||
});
|
||||
}
|
||||
|
||||
void WasmPromiseTest::allWithFinallyAndThrow()
|
||||
{
|
||||
init();
|
||||
|
||||
val promise1 = m_testSupport.call<val>("makeTestPromise", val("promise1"));
|
||||
val promise2 = m_testSupport.call<val>("makeTestPromise", val("promise2"));
|
||||
val promise3 = m_testSupport.call<val>("makeTestPromise", val("promise3"));
|
||||
|
||||
auto finallyCalledOnce = std::shared_ptr<bool>();
|
||||
*finallyCalledOnce = true;
|
||||
|
||||
qstdweb::Promise::all({promise1, promise2, promise3}, {
|
||||
.thenFunc = [](val result) {
|
||||
Q_UNUSED(result);
|
||||
EM_ASM({
|
||||
throw "This breaks it all!!!";
|
||||
});
|
||||
},
|
||||
.finallyFunc = [finallyCalledOnce]() {
|
||||
QWASMVERIFY(*finallyCalledOnce);
|
||||
*finallyCalledOnce = false;
|
||||
QWASMSUCCESS();
|
||||
}
|
||||
});
|
||||
|
||||
EM_ASM({
|
||||
testSupport.resolve["promise3"]("Data 3");
|
||||
testSupport.resolve["promise1"]("Data 1");
|
||||
testSupport.resolve["promise2"]("Data 2");
|
||||
});
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
auto testObject = std::make_shared<WasmPromiseTest>();
|
||||
QtWasmTest::initTestCase<QCoreApplication>(argc, argv, testObject);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "promise_main.moc"
|
10
tests/manual/wasm/qstdweb/qwasmcompositor_auto.html
Normal file
10
tests/manual/wasm/qstdweb/qwasmcompositor_auto.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!doctype html>
|
||||
<script type="text/javascript" src="qtwasmtestlib.js"></script>
|
||||
<script type="text/javascript" src="qwasmcompositor_auto.js"></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
runTestCase(document.getElementById("log"));
|
||||
};
|
||||
</script>
|
||||
<p>Running files auto test.</p>
|
||||
<div id="log"></div>
|
174
tests/manual/wasm/qstdweb/qwasmcompositor_main.cpp
Normal file
174
tests/manual/wasm/qstdweb/qwasmcompositor_main.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtCore/QEvent>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtGui/qoffscreensurface.h>
|
||||
#include <QtGui/qpa/qwindowsysteminterface.h>
|
||||
#include <QtGui/private/qrhigles2_p.h>
|
||||
|
||||
#include <qtwasmtestlib.h>
|
||||
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace tst_qwasmcompositor_internal {
|
||||
namespace {
|
||||
class Window : public QWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Window();
|
||||
~Window() override { qDebug() << "dtor Window"; }
|
||||
|
||||
void keyPressEvent(QKeyEvent *) final;
|
||||
|
||||
signals:
|
||||
void exposed();
|
||||
void keyEventReceived();
|
||||
void initFailed();
|
||||
|
||||
protected:
|
||||
private:
|
||||
void init();
|
||||
|
||||
void exposeEvent(QExposeEvent *) override;
|
||||
bool m_exposedOnce = false;
|
||||
|
||||
std::unique_ptr<QOffscreenSurface> m_fallbackSurface;
|
||||
std::unique_ptr<QRhi> m_rhi;
|
||||
};
|
||||
|
||||
Window::Window()
|
||||
{
|
||||
setSurfaceType(OpenGLSurface);
|
||||
}
|
||||
|
||||
void Window::exposeEvent(QExposeEvent *)
|
||||
{
|
||||
if (isExposed() && !m_exposedOnce) {
|
||||
m_exposedOnce = true;
|
||||
init();
|
||||
emit exposed();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::keyPressEvent(QKeyEvent *)
|
||||
{
|
||||
emit keyEventReceived();
|
||||
}
|
||||
|
||||
void Window::init()
|
||||
{
|
||||
QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers | QRhi::EnableProfiling;
|
||||
|
||||
m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface());
|
||||
QRhiGles2InitParams params;
|
||||
params.fallbackSurface = m_fallbackSurface.get();
|
||||
params.window = this;
|
||||
|
||||
// Double init of RHI causes the OpenGL context to be destroyed, which causes a bug with input.
|
||||
m_rhi.reset(QRhi::create(QRhi::OpenGLES2, ¶ms, rhiFlags));
|
||||
m_rhi.reset(QRhi::create(QRhi::OpenGLES2, ¶ms, rhiFlags));
|
||||
|
||||
if (!m_rhi)
|
||||
emit initFailed();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tst_qwasmcompositor_internal
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
class QWasmCompositorTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QWasmCompositorTest() : m_window(val::global("window")), m_testSupport(val::object())
|
||||
{
|
||||
m_window.set("testSupport", m_testSupport);
|
||||
m_testSupport.set("qtAddContainerElement",
|
||||
emscripten::val::module_property("qtAddContainerElement"));
|
||||
m_testSupport.set("qtRemoveContainerElement",
|
||||
emscripten::val::module_property("qtRemoveContainerElement"));
|
||||
}
|
||||
|
||||
~QWasmCompositorTest() noexcept
|
||||
{
|
||||
qDebug() << this << "In dtor";
|
||||
for (auto it = m_cleanup.rbegin(); it != m_cleanup.rend(); ++it)
|
||||
(*it)();
|
||||
m_window.set("testSupport", emscripten::val::undefined());
|
||||
}
|
||||
|
||||
private:
|
||||
void init()
|
||||
{
|
||||
EM_ASM({
|
||||
testSupport.screenElement = document.createElement("div");
|
||||
testSupport.screenElement.id = "test-canvas-qwasmcompositor";
|
||||
document.body.appendChild(testSupport.screenElement);
|
||||
});
|
||||
m_cleanup.emplace_back([]() mutable {
|
||||
EM_ASM({
|
||||
testSupport.qtRemoveContainerElement(testSupport.screenElement);
|
||||
testSupport.screenElement.parentElement.removeChild(testSupport.screenElement);
|
||||
});
|
||||
});
|
||||
|
||||
EM_ASM({ testSupport.qtAddContainerElement(testSupport.screenElement); });
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *Own(T *plainPtr)
|
||||
{
|
||||
m_cleanup.emplace_back([plainPtr]() mutable { delete plainPtr; });
|
||||
return plainPtr;
|
||||
}
|
||||
|
||||
val m_window;
|
||||
val m_testSupport;
|
||||
|
||||
std::vector<std::function<void()>> m_cleanup;
|
||||
|
||||
private slots:
|
||||
void testReceivingKeyboardEventsAfterOpenGLContextReset();
|
||||
};
|
||||
|
||||
void QWasmCompositorTest::testReceivingKeyboardEventsAfterOpenGLContextReset()
|
||||
{
|
||||
init();
|
||||
|
||||
using Window = tst_qwasmcompositor_internal::Window;
|
||||
Window *window = Own(new Window);
|
||||
window->show();
|
||||
window->requestActivate();
|
||||
|
||||
QWindowSystemInterface::flushWindowSystemEvents();
|
||||
|
||||
QObject::connect(window, &Window::keyEventReceived, []() { QWASMSUCCESS(); });
|
||||
QObject::connect(window, &Window::initFailed,
|
||||
[]() { QWASMFAIL("Cannot initialize test window"); });
|
||||
QObject::connect(window, &Window::exposed, []() {
|
||||
EM_ASM({
|
||||
testSupport.screenElement.shadowRoot.querySelector('.qt-window')
|
||||
.dispatchEvent(new KeyboardEvent('keydown', { key : 'a' }));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
auto testObject = std::make_shared<QWasmCompositorTest>();
|
||||
QtWasmTest::initTestCase<QGuiApplication>(argc, argv, testObject);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "qwasmcompositor_main.moc"
|
Reference in New Issue
Block a user