// Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include #include class tst_LocalFileApi : public QObject { Q_OBJECT private: emscripten::val makeAccept(std::vector types) { auto accept = emscripten::val::object(); accept.set("application/octet-stream", emscripten::val::array(std::move(types))); return accept; } emscripten::val makeType(QString description, std::vector acceptExtensions) { using namespace emscripten; auto type = val::object(); type.set("description", description.toStdString()); auto accept = val::object(); accept.set("application/octet-stream", val::array(std::move(acceptExtensions))); type.set("accept", makeAccept(std::move(acceptExtensions))); return type; } emscripten::val makeOpenFileOptions(bool acceptMultiple, std::vector types) { using namespace emscripten; auto webFilter = val::object(); webFilter.set("types", val::array(std::move(types))); if (!types.empty()) webFilter.set("excludeAcceptAllOption", val(true)); webFilter.set("multiple", val(acceptMultiple)); return webFilter; } emscripten::val makeSaveFileOptions(QString suggestedName, std::vector types) { using namespace emscripten; auto webFilter = val::object(); webFilter.set("suggestedName", val(suggestedName.toStdString())); webFilter.set("types", val::array(std::move(types))); return webFilter; } private Q_SLOTS: void fileExtensionFilterTransformation_data(); void fileExtensionFilterTransformation(); void acceptTransformation_data(); void acceptTransformation(); void typeTransformation_data(); void typeTransformation(); void openFileOptions_data(); void openFileOptions(); void saveFileOptions_data(); void saveFileOptions(); void fileInputAccept_data(); void fileInputAccept(); }; bool valDeepEquals(emscripten::val lhs, emscripten::val rhs) { auto json = emscripten::val::global("JSON"); auto lhsAsJsonString = json.call("stringify", lhs); auto rhsAsJsonString = json.call("stringify", rhs); return lhsAsJsonString.equals(rhsAsJsonString); } void tst_LocalFileApi::fileExtensionFilterTransformation_data() { QTest::addColumn("qtFileFilter"); QTest::addColumn>("expectedWebExtensionFilter"); QTest::newRow("PNG extension with an asterisk") << QString("*.png") << std::make_optional(".png"); QTest::newRow("Long extension with an asterisk") << QString("*.someotherfile") << std::make_optional(".someotherfile"); QTest::newRow(".dat with no asterisk") << QString(".dat") << std::make_optional(".dat"); QTest::newRow("Multiple asterisks") << QString("*ot*.abc") << std::optional(); QTest::newRow("Filename") << QString("abcd.abc") << std::optional(); QTest::newRow("match all") << QString("*.*") << std::optional(); } void tst_LocalFileApi::fileExtensionFilterTransformation() { QFETCH(QString, qtFileFilter); QFETCH(std::optional, expectedWebExtensionFilter); auto result = LocalFileApi::Type::Accept::MimeType::Extension::fromQt(qtFileFilter); if (expectedWebExtensionFilter) { QCOMPARE_EQ(expectedWebExtensionFilter, result->value()); } else { QVERIFY(!result.has_value()); } } void tst_LocalFileApi::acceptTransformation_data() { using namespace emscripten; QTest::addColumn("qtFilterList"); QTest::addColumn("expectedExtensionList"); QTest::newRow("Multiple types") << QString("*.png *.other *.txt") << QStringList{ ".png", ".other", ".txt" }; QTest::newRow("Single type") << QString("*.png") << QStringList{ ".png" }; QTest::newRow("No filter when accepts all") << QString("*.*") << QStringList(); QTest::newRow("No filter when one filter accepts all") << QString("*.* *.jpg") << QStringList(); QTest::newRow("Weird spaces") << QString(" *.jpg *.png *.icon ") << QStringList{ ".jpg", ".png", ".icon" }; } void tst_LocalFileApi::acceptTransformation() { QFETCH(QString, qtFilterList); QFETCH(QStringList, expectedExtensionList); auto result = LocalFileApi::Type::Accept::fromQt(qtFilterList); if (expectedExtensionList.isEmpty()) { QVERIFY(!result.has_value()); } else { QStringList transformed; std::transform(result->mimeType().extensions().begin(), result->mimeType().extensions().end(), std::back_inserter(transformed), [](const LocalFileApi::Type::Accept::MimeType::Extension &extension) { return extension.value().toString(); }); QCOMPARE_EQ(expectedExtensionList, transformed); } } void tst_LocalFileApi::typeTransformation_data() { using namespace emscripten; QTest::addColumn("qtFilterList"); QTest::addColumn("expectedDescription"); QTest::addColumn("expectedExtensions"); QTest::newRow("With description") << QString("Text files (*.txt)") << QString("Text files") << QStringList{ ".txt" }; QTest::newRow("No description") << QString("*.jpg") << QString("") << QStringList{ ".jpg" }; } void tst_LocalFileApi::typeTransformation() { QFETCH(QString, qtFilterList); QFETCH(QString, expectedDescription); QFETCH(QStringList, expectedExtensions); auto result = LocalFileApi::Type::fromQt(qtFilterList); QCOMPARE_EQ(result->description(), expectedDescription); QStringList transformed; std::transform(result->accept()->mimeType().extensions().begin(), result->accept()->mimeType().extensions().end(), std::back_inserter(transformed), [](const LocalFileApi::Type::Accept::MimeType::Extension &extension) { return extension.value().toString(); }); QCOMPARE_EQ(expectedExtensions, transformed); } void tst_LocalFileApi::openFileOptions_data() { using namespace emscripten; QTest::addColumn("qtFilterList"); QTest::addColumn("multiple"); QTest::addColumn("expectedWebType"); QTest::newRow("Multiple files") << QStringList({"Text files (*.txt)", "Images (*.jpg *.png)", "*.bat"}) << true << makeOpenFileOptions(true, { makeType("Text files", { val(".txt")}), makeType("Images", { val(".jpg"), val(".png")}), makeType("", { val(".bat")})}); QTest::newRow("Single file") << QStringList({"Text files (*.txt)", "Images (*.jpg *.png)", "*.bat"}) << false << makeOpenFileOptions(false, { makeType("Text files", { val(".txt")}), makeType("Images", { val(".jpg"), val(".png")}), makeType("", { val(".bat")})}); } void tst_LocalFileApi::openFileOptions() { QFETCH(QStringList, qtFilterList); QFETCH(bool, multiple); QFETCH(emscripten::val, expectedWebType); auto result = LocalFileApi::makeOpenFileOptions(qtFilterList, multiple); QVERIFY(valDeepEquals(result, expectedWebType)); } void tst_LocalFileApi::saveFileOptions_data() { using namespace emscripten; QTest::addColumn("qtFilterList"); QTest::addColumn("suggestedName"); QTest::addColumn("expectedWebType"); QTest::newRow("Multiple files") << QStringList({"Text files (*.txt)", "Images (*.jpg *.png)", "*.bat"}) << "someName1" << makeSaveFileOptions("someName1", { makeType("Text files", { val(".txt")}), makeType("Images", { val(".jpg"), val(".png")}), makeType("", { val(".bat")})}); QTest::newRow("Single file") << QStringList({"Text files (*.txt)", "Images (*.jpg *.png)", "*.bat"}) << "some name 2" << makeSaveFileOptions("some name 2", { makeType("Text files", { val(".txt")}), makeType("Images", { val(".jpg"), val(".png")}), makeType("", { val(".bat")})}); } void tst_LocalFileApi::saveFileOptions() { QFETCH(QStringList, qtFilterList); QFETCH(QString, suggestedName); QFETCH(emscripten::val, expectedWebType); auto result = LocalFileApi::makeSaveFileOptions(qtFilterList, suggestedName.toStdString()); QVERIFY(valDeepEquals(result, expectedWebType)); } void tst_LocalFileApi::fileInputAccept_data() { using namespace emscripten; QTest::addColumn("qtFilterList"); QTest::addColumn("expectedAccept"); QTest::newRow("Multiple files") << QStringList{ "Text files (*.txt)", "Images (*.jpg *.png)", "*.bat" } << ".txt,.jpg,.png,.bat"; QTest::newRow("Spaces") << QStringList{ " Documents (*.doc)", "Everything (*.*)", " Stuff ( *.stf *.tng)", " *.exe" } << ".doc,.stf,.tng,.exe"; } void tst_LocalFileApi::fileInputAccept() { QFETCH(QStringList, qtFilterList); QFETCH(QString, expectedAccept); auto result = LocalFileApi::makeFileInputAccept(qtFilterList); QCOMPARE_EQ(expectedAccept, QString::fromStdString(result)); } QTEST_APPLESS_MAIN(tst_LocalFileApi) #include "tst_localfileapi.moc"