79cc3ae201
The polyfill for file input on WASM now makes use of the supplied filter list. Some changes were introduced in the abstraction for filters so that they are usable both for the new file API and the legacy file input. Change-Id: Id6341be4d6a1647e17382d13da7be42491cfaf80 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
261 lines
9.4 KiB
C++
261 lines
9.4 KiB
C++
// Copyright (C) 2022 The Qt Company Ltd.
|
|
// Copyright (C) 2016 Intel Corporation.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
#include <QtGui/private/qlocalfileapi_p.h>
|
|
#include <QTest>
|
|
#include <emscripten/val.h>
|
|
|
|
class tst_LocalFileApi : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private:
|
|
emscripten::val makeAccept(std::vector<emscripten::val> 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<emscripten::val> 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<emscripten::val> 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<emscripten::val> 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<emscripten::val>("stringify", lhs);
|
|
auto rhsAsJsonString = json.call<emscripten::val>("stringify", rhs);
|
|
|
|
return lhsAsJsonString.equals(rhsAsJsonString);
|
|
}
|
|
|
|
void tst_LocalFileApi::fileExtensionFilterTransformation_data()
|
|
{
|
|
QTest::addColumn<QString>("qtFileFilter");
|
|
QTest::addColumn<std::optional<QString>>("expectedWebExtensionFilter");
|
|
|
|
QTest::newRow("PNG extension with an asterisk")
|
|
<< QString("*.png") << std::make_optional<QString>(".png");
|
|
QTest::newRow("Long extension with an asterisk")
|
|
<< QString("*.someotherfile") << std::make_optional<QString>(".someotherfile");
|
|
QTest::newRow(".dat with no asterisk")
|
|
<< QString(".dat") << std::make_optional<QString>(".dat");
|
|
QTest::newRow("Multiple asterisks") << QString("*ot*.abc") << std::optional<QString>();
|
|
QTest::newRow("Filename") << QString("abcd.abc") << std::optional<QString>();
|
|
QTest::newRow("match all") << QString("*.*") << std::optional<QString>();
|
|
}
|
|
|
|
void tst_LocalFileApi::fileExtensionFilterTransformation()
|
|
{
|
|
QFETCH(QString, qtFileFilter);
|
|
QFETCH(std::optional<QString>, 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<QString>("qtFilterList");
|
|
QTest::addColumn<QStringList>("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<QString>("qtFilterList");
|
|
QTest::addColumn<QString>("expectedDescription");
|
|
QTest::addColumn<QStringList>("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<QStringList>("qtFilterList");
|
|
QTest::addColumn<bool>("multiple");
|
|
QTest::addColumn<emscripten::val>("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<QStringList>("qtFilterList");
|
|
QTest::addColumn<QString>("suggestedName");
|
|
QTest::addColumn<emscripten::val>("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<QStringList>("qtFilterList");
|
|
QTest::addColumn<QString>("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"
|