diff --git a/docs/folder-source-contract.md b/docs/folder-source-contract.md index 88b17ae6d..3387c536e 100644 --- a/docs/folder-source-contract.md +++ b/docs/folder-source-contract.md @@ -100,8 +100,6 @@ provider 暂时缺失时,合法引用保持不变,可保存为占位驻留 ## 验证 -Shell 的 `taskmanager_qml_api` 测试使用真实 Qt 测试插件覆盖固定、重复拒绝、模型角色传递、 -变化通知、顺序保存、未知插件恢复和取消固定释放对象。 任务栏 `FolderPopup.qml` 统一处理普通目录和文管内容页面;`frame_qml` 覆盖共享弹窗生命周期。 文管插件的独立测试覆盖动态加载、真实 QML 页面、多个目录独立导航、文件增删改名、 目录删除后重建、固定目录重命名后跟随并上报新身份、固定目录被删除时上报内容丢失 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 574f148c3..76f015896 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,7 +20,7 @@ add_custom_target(coverage find_program(QML_TEST_RUNNER NAMES qmltestrunner6 qmltestrunner HINTS /usr/lib/qt${QT_VERSION_MAJOR}/bin) if(QML_TEST_RUNNER) - foreach(_suite frame/qml panels/dock/taskmanager/qml) + foreach(_suite frame/qml) string(REPLACE "/" "_" _name "${_suite}") add_test(NAME ${_name} COMMAND ${CMAKE_COMMAND} -E env @@ -29,9 +29,4 @@ if(QML_TEST_RUNNER) ${QML_TEST_RUNNER} -input "${CMAKE_CURRENT_SOURCE_DIR}/${_suite}" -import "${CMAKE_BINARY_DIR}/plugins") endforeach() - add_custom_target(folder_qml_tests - DEPENDS dde-shell-plugin dde-shell-dock dock-plugin - COMMAND ${CMAKE_CTEST_COMMAND} --test-dir "${CMAKE_BINARY_DIR}" - -R "^(frame_qml|panels_dock_taskmanager_qml)$" --output-on-failure - VERBATIM) endif() diff --git a/tests/panels/dock/taskmanager/CMakeLists.txt b/tests/panels/dock/taskmanager/CMakeLists.txt index 6ed3f1d4c..2131b6770 100644 --- a/tests/panels/dock/taskmanager/CMakeLists.txt +++ b/tests/panels/dock/taskmanager/CMakeLists.txt @@ -59,26 +59,3 @@ add_executable(foldermenuregistry_tests target_include_directories(foldermenuregistry_tests PRIVATE ${CMAKE_SOURCE_DIR}/panels/dock/taskmanager) target_link_libraries(foldermenuregistry_tests PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Test) add_test(NAME folder_menu_registry COMMAND foldermenuregistry_tests) - -# Exercise the real backend through Applet's QML attached-type lookup, not just -# QObject/QMetaObject invocation (capitalized D-Bus methods differ here). -add_executable(taskmanagerqmlapi_tests taskmanagerqmlapitests.cpp) -# Inject the folder model without starting window monitoring or D-Bus services, -# as in the other dock tests that access private model state. -target_compile_options(taskmanagerqmlapi_tests PRIVATE -fno-access-control) -add_library(test-folder-provider MODULE testfolderprovider.cpp) -target_link_libraries(test-folder-provider PRIVATE dde-shell-dock) -set_target_properties(test-folder-provider PROPERTIES PREFIX "" - OUTPUT_NAME "org.deepin.ds.folderprovider.testsource" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/plugins") -target_compile_definitions(taskmanagerqmlapi_tests PRIVATE - TEST_FOLDER_PLUGIN_DIR="${CMAKE_CURRENT_BINARY_DIR}/plugins" - TEST_SHELL_QML_DIR="${CMAKE_BINARY_DIR}/plugins" - TEST_TASKMANAGER_PACKAGE="${CMAKE_SOURCE_DIR}/panels/dock/taskmanager/package") -add_dependencies(taskmanagerqmlapi_tests test-folder-provider) -target_include_directories(taskmanagerqmlapi_tests PRIVATE ${CMAKE_SOURCE_DIR}/panels/dock/taskmanager) -target_link_libraries(taskmanagerqmlapi_tests PRIVATE dock-taskmanager dde-shell-dock Qt${QT_VERSION_MAJOR}::Qml Qt${QT_VERSION_MAJOR}::Test) -add_test(NAME taskmanager_qml_api COMMAND taskmanagerqmlapi_tests) -# Debian builds disable build RPATH; use the plugin and frame from this build. -set_tests_properties(taskmanager_qml_api PROPERTIES ENVIRONMENT - "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software;LD_LIBRARY_PATH=$:$:$") diff --git a/tests/panels/dock/taskmanager/qml/tst_foldercomponents.qml b/tests/panels/dock/taskmanager/qml/tst_foldercomponents.qml deleted file mode 100644 index 2666e9a6a..000000000 --- a/tests/panels/dock/taskmanager/qml/tst_foldercomponents.qml +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later -import QtQuick -import QtTest -import "../../../../../panels/dock/taskmanager/package" as TaskItems - -TestCase { - name: "FolderComponents" - when: windowShown - visible: true - width: 100; height: 100 - TaskItems.FolderIcon { - id: icon - width: 64; height: 64 - } - function test_preview_data() { - return [{tag: "empty", count: 0}, {tag: "one", count: 1}, - {tag: "four", count: 4}, {tag: "overflow", count: 8}] - } - function test_preview(data) { - let entries = [] - for (let i = 0; i < data.count; ++i) - entries.push({id: "app" + i, name: "App " + i, iconName: "folder"}) - icon.contents = entries - for (let slot = 0; slot < 4; ++slot) { - let preview = findChild(icon, "folderPreview" + slot) - verify(preview !== null) - compare(preview.visible, slot < data.count) - if (slot < data.count) compare(preview.name, "folder") - } - // Empty folders must still read as a folder instead of a blank square. - let placeholder = findChild(icon, "folderPlaceholder") - verify(placeholder !== null) - compare(placeholder.visible, data.count === 0) - compare(placeholder.name, "folder") - // ...and they must not paint the translucent preview plate behind it. - compare(icon.color.a, data.count === 0 ? 0 : 0.2) - } - Component { - id: folderMenuComponent - TaskItems.FolderContextMenu {} - } - QtObject { - id: menuRegistry - property var dispatched: [] - function triggerFolderMenuAction(type, folderId, actionId) { - dispatched = dispatched.concat([{type: type, folderId: folderId, actionId: actionId}]) - } - } - SignalSpy { id: openSpy; signalName: "openRequested" } - SignalSpy { id: undockSpy; signalName: "undockRequested" } - - function test_folderMenuDispatch() { - const menu = createTemporaryObject(folderMenuComponent, this, { - registry: menuRegistry, - folderType: "launcher", - folderId: "internal/folders/12", - entries: [{id: "open-folder", name: "My folder"}, - {id: "undock-folder", name: "Undock"}] - }) - verify(menu !== null) - openSpy.target = menu - undockSpy.target = menu - openSpy.clear() - undockSpy.clear() - menuRegistry.dispatched = [] - tryCompare(menu.items, "length", 2) - compare(menu.items[0].text, "My folder") - compare(menu.items[0].enabled, true) - menu.items[0].triggered() - compare(openSpy.count, 1) - compare(undockSpy.count, 0) - menu.items[1].triggered() - compare(openSpy.count, 1) - compare(undockSpy.count, 1) - compare(menuRegistry.dispatched.length, 0) - - menu.entries = menu.entries.concat([ - {id: "details", name: "Details", checkable: true, checked: true}, - {id: "disabled", name: "Unavailable", enabled: false} - ]) - tryCompare(menu.items, "length", 4) - compare(menu.items[2].checkable, true) - compare(menu.items[2].checked, true) - compare(menu.items[3].enabled, false) - menu.items[2].triggered() - compare(menuRegistry.dispatched.length, 1) - compare(menuRegistry.dispatched[0].type, "launcher") - compare(menuRegistry.dispatched[0].folderId, "internal/folders/12") - compare(menuRegistry.dispatched[0].actionId, "details") - compare(openSpy.count, 1) - compare(undockSpy.count, 1) - openSpy.target = null - undockSpy.target = null - } - function test_popupAndMenuCompile() { - for (const name of ["FolderPopup.qml", "FolderContextMenu.qml", "FolderApplicationMenu.qml"]) { - const component = Qt.createComponent(Qt.resolvedUrl("../../../../../panels/dock/taskmanager/package/" + name)) - compare(component.status, Component.Ready, component.errorString()) - component.destroy() - } - } -} diff --git a/tests/panels/dock/taskmanager/taskmanagerqmlapitests.cpp b/tests/panels/dock/taskmanager/taskmanagerqmlapitests.cpp deleted file mode 100644 index d755d7b57..000000000 --- a/tests/panels/dock/taskmanager/taskmanagerqmlapitests.cpp +++ /dev/null @@ -1,366 +0,0 @@ -// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later -#include "taskmanager.h" -#include "abstractwindowmonitor.h" -#include "taskmanagersettings.h" -#include "appletitem.h" -#include "dockglobalelementmodel.h" -#include "dockitemmodel.h" -#include "foldercontent.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class ApplicationFolderModel : public QStandardItemModel -{ - Q_OBJECT -public: - int contentsQueries = 0; - QVariantList contents{QVariantMap{{"id", "app"}, {"name", "App"}, {"iconName", "folder"}}}; - ApplicationFolderModel() - { - setItemRoleNames({{dock::TaskManager::DesktopIdRole, "desktopId"}, {dock::TaskManager::NameRole, "name"}}); - auto folder = new QStandardItem; - folder->setData("internal/folders/1", dock::TaskManager::DesktopIdRole); - folder->setData("Applications", dock::TaskManager::NameRole); - appendRow(folder); - } - Q_INVOKABLE QVariantMap folderInfo(const QString &) - { - ++contentsQueries; - return {{"contents", contents}}; - } -signals: - void arrangementChanged(); -}; - -class TaskManagerQmlApiTest : public QObject -{ - Q_OBJECT -private slots: - void cleanup() { dock::TaskManagerSettings::instance()->setDockedElements({}); } - - void providerLibraryIsDiscovered() - { - const QString directory = QStringLiteral(TEST_FOLDER_PLUGIN_DIR); - const QString library = directory + "/org.deepin.ds.folderprovider.testsource.so"; - QVERIFY(QFileInfo::exists(library)); - // Use the actual MODULE filename. An extensionless existence check - // used to skip the provider before QPluginLoader could load it. - QVERIFY(!QFileInfo::exists(directory + "/org.deepin.ds.folderprovider.testsource")); - QCoreApplication::addLibraryPath(directory); - const QString reference = dock::FolderContentRegistry::reference("testsource", "test://folder"); - QCOMPARE(dock::FolderContentRegistry::instance()->normalizeReference(reference), reference); - // Missing providers also preserve references. Verify that the plugin - // actually implements the Dock interface and supplies its presentation. - QScopedPointer presentation(dock::FolderContentRegistry::instance()->create(reference, nullptr)); - QVERIFY(presentation); - QCOMPARE(presentation->title(), QStringLiteral("Test folder")); - QCOMPARE(presentation->previewIcons(), QVariantList{QUrl("image://icon/folder")}); - } - - void appItemComponentCompiles() - { - // The backend registers the TextCalculator QML module used by AppItem. - dock::TaskManager backend; - QQmlEngine engine; - engine.addImportPath(QStringLiteral(TEST_SHELL_QML_DIR)); - QQmlComponent component(&engine, QUrl::fromLocalFile(QStringLiteral(TEST_TASKMANAGER_PACKAGE "/AppItem.qml"))); - QTRY_VERIFY(component.status() != QQmlComponent::Loading); - QVERIFY2(component.isReady(), qPrintable(component.errorString())); - } - - void applicationFolderMetadataAndSingleRefresh() - { - QStandardItemModel apps, windows; - ApplicationFolderModel folders; - dock::DockCombineModel active(&windows, &apps, dock::TaskManager::DesktopIdRole, - [](QVariant, QAbstractItemModel *) { return QModelIndex(); }); - dock::DockGlobalElementModel global(&apps, &active); - global.setApplicationFolderModel(&folders); - dock::TaskManagerSettings::instance()->setDockedElements({"internal/folders/1"}); - QTRY_COMPARE(global.rowCount(), 1); - const auto folder = global.index(0, 0); - QCOMPARE(folder.data(dock::TaskManager::NameRole).toString(), "Applications"); - QCOMPARE(folder.data(dock::TaskManager::MenusRole).toString(), "[]"); - QCOMPARE(folders.contentsQueries, 0); - QCOMPARE(folder.data(dock::TaskManager::ApplicationFolderContentsRole).toList(), folders.contents); - QCOMPARE(folders.contentsQueries, 1); - - QSignalSpy changed(&global, &QAbstractItemModel::dataChanged); - folders.setData(folders.index(0, 0), "Renamed", dock::TaskManager::NameRole); - folders.contents.clear(); - emit folders.arrangementChanged(); - QCOMPARE(changed.count(), 1); - const auto roles = changed.first().at(2).value>(); - QVERIFY(roles.contains(dock::TaskManager::NameRole)); - QVERIFY(roles.contains(dock::TaskManager::ApplicationFolderContentsRole)); - QCOMPARE(folder.data(dock::TaskManager::NameRole).toString(), "Renamed"); - QVERIFY(folder.data(dock::TaskManager::ApplicationFolderContentsRole).toList().isEmpty()); - - folders.removeRow(0); - emit folders.arrangementChanged(); - QCOMPARE(global.rowCount(), 0); - QVERIFY(dock::TaskManagerSettings::instance()->dockedElements().isEmpty()); - } - - void contentPinAndModel() - { - QCoreApplication::addLibraryPath(QStringLiteral(TEST_FOLDER_PLUGIN_DIR)); - dock::TaskManager backend; - auto settings = dock::TaskManagerSettings::instance(); - settings->setDockedElements({}); - QStandardItemModel apps, windows; - dock::DockCombineModel active(&windows, &apps, dock::TaskManager::DesktopIdRole, - [](QVariant, QAbstractItemModel *) { return QModelIndex(); }); - dock::DockGlobalElementModel global(&apps, &active); - dock::DockItemModel visible(&global); - const QString reference = dock::FolderContentRegistry::reference("testsource", "test://folder"); - QVERIFY(backend.requestDockByDesktopId(reference)); - QVERIFY(backend.IsDocked(reference)); - QVERIFY(!backend.requestDockByDesktopId(reference)); - QCOMPARE(settings->dockedElements(), QStringList{reference}); - QTRY_COMPARE(visible.rowCount(), 1); - auto index = visible.index(0, 0); - QCOMPARE(index.data(dock::TaskManager::ItemIdRole).toString(), reference); - QCOMPARE(index.data(dock::TaskManager::FolderTypeRole).toString(), QStringLiteral("testsource")); - QCOMPARE(visible.roleNames().value(dock::TaskManager::ApplicationFolderContentsRole), QByteArray("applicationFolderContents")); - QVERIFY(index.data(dock::TaskManager::ApplicationFolderContentsRole).toList().isEmpty()); - QPointer presentation = index.data(dock::TaskManager::FolderPresentationRole).value(); - QVERIFY(presentation); - QSignalSpy changed(&visible, &QAbstractItemModel::dataChanged); - QVERIFY(QMetaObject::invokeMethod(presentation, "rename", Q_ARG(QString, "Updated folder"))); - QTRY_VERIFY(!changed.isEmpty()); - QCOMPARE(index.data(dock::TaskManager::NameRole).toString(), QStringLiteral("Updated folder")); - - // A missing provider must not lose a restored pin or change its ID. - const QString missing = dock::FolderContentRegistry::reference("unavailable", "other-id"); - settings->setDockedElements({reference, missing}); - QTRY_COMPARE(visible.rowCount(), 2); - QCOMPARE(visible.index(1, 0).data(dock::TaskManager::FolderTypeRole).toString(), QStringLiteral("unavailable")); - QVERIFY(visible.index(1, 0).data(dock::TaskManager::FolderPresentationRole).value()); - backend.saveDockElementsOrder({missing, reference, missing}); - QCOMPARE(settings->dockedElements(), (QStringList{missing, reference})); - QVERIFY(backend.requestUndockByDesktopId(reference)); - QTRY_COMPARE(visible.rowCount(), 1); - QTRY_VERIFY(presentation.isNull()); - QCOMPARE(visible.index(0, 0).data(dock::TaskManager::ItemIdRole).toString(), missing); - QVERIFY(backend.requestUndockByDesktopId(missing)); - QTRY_COMPARE(visible.rowCount(), 0); - QVERIFY(!backend.requestDockByDesktopId("folder/../invalid")); - QVERIFY(!backend.requestDockByDesktopId(dock::FolderContentRegistry::reference("testsource", "invalid-id"))); - } - - void restoredContentReferences_data() - { - QTest::addColumn("source"); - QTest::addColumn("id"); - QTest::addColumn("normalizedId"); - QTest::addColumn("visible"); - QTest::newRow("valid") << "testsource" << "test://folder" << "test://folder" << true; - QTest::newRow("rejected") << "testsource" << "invalid-id" << "" << false; - QTest::newRow("noncanonical") << "testsource" << "test://folder/" << "test://folder" << false; - QTest::newRow("unavailable") << "unavailable" << "other-id" << "other-id" << true; - } - - void restoredContentReferences() - { - QFETCH(QString, source); - QFETCH(QString, id); - QFETCH(QString, normalizedId); - QFETCH(bool, visible); - QCoreApplication::addLibraryPath(QStringLiteral(TEST_FOLDER_PLUGIN_DIR)); - const auto reference = dock::FolderContentRegistry::reference(source, id); - const auto normalized = normalizedId.isEmpty() ? QString() - : dock::FolderContentRegistry::reference(source, normalizedId); - QVERIFY(dock::FolderContentRegistry::isReference(reference)); - QCOMPARE(dock::FolderContentRegistry::instance()->normalizeReference(reference), normalized); - - QStandardItemModel apps, windows; - dock::DockCombineModel active(&windows, &apps, dock::TaskManager::DesktopIdRole, - [](QVariant, QAbstractItemModel *) { return QModelIndex(); }); - dock::DockGlobalElementModel global(&apps, &active); - auto settings = dock::TaskManagerSettings::instance(); - // Restore directly from settings, bypassing the pinning API's validation. - settings->setDockedElements({reference}); - QCOMPARE(global.rowCount(), visible ? 1 : 0); - QCOMPARE(settings->dockedElements(), QStringList{reference}); - if (visible) { - const auto index = global.index(0, 0); - QCOMPARE(index.data(dock::TaskManager::ItemIdRole).toString(), reference); - QVERIFY(index.data(dock::TaskManager::FolderPresentationRole).value()); - } else { - QVERIFY(global.findChildren().isEmpty()); - } - } - - void unavailableProviderPin() - { - dock::TaskManager backend; - QStandardItemModel apps, windows; - dock::DockCombineModel active(&windows, &apps, dock::TaskManager::DesktopIdRole, - [](QVariant, QAbstractItemModel *) { return QModelIndex(); }); - dock::DockGlobalElementModel global(&apps, &active); - const QString reference = dock::FolderContentRegistry::reference("unavailable", "other-id"); - QCOMPARE(dock::FolderContentRegistry::instance()->normalizeReference(reference), reference); - QVERIFY(backend.requestDockByDesktopId(reference)); - QVERIFY(backend.IsDocked(reference)); - QVERIFY(!backend.requestDockByDesktopId(reference)); - QCOMPARE(dock::TaskManagerSettings::instance()->dockedElements(), QStringList{reference}); - QTRY_COMPARE(global.rowCount(), 1); - auto object = global.index(0, 0).data(dock::TaskManager::FolderPresentationRole).value(); - QPointer presentation = qobject_cast(object); - QVERIFY(presentation); - QVERIFY(presentation->contentUrl().isEmpty()); - QVERIFY(backend.requestUndockByDesktopId(reference)); - QTRY_COMPARE(global.rowCount(), 0); - QTRY_VERIFY(presentation.isNull()); - } - - // A rename on disk makes the provider resolve a new id. The persisted pin - // must be rewritten, otherwise it keeps pointing at a path that no longer - // exists and the dock entry becomes a dead folder. - void contentPinFollowsRename() - { - QCoreApplication::addLibraryPath(QStringLiteral(TEST_FOLDER_PLUGIN_DIR)); - dock::TaskManager backend; - auto settings = dock::TaskManagerSettings::instance(); - settings->setDockedElements({}); - QStandardItemModel apps, windows; - dock::DockCombineModel active(&windows, &apps, dock::TaskManager::DesktopIdRole, - [](QVariant, QAbstractItemModel *) { return QModelIndex(); }); - dock::DockGlobalElementModel global(&apps, &active); - dock::DockItemModel visible(&global); - - const QString reference = dock::FolderContentRegistry::reference("testsource", "test://folder"); - QVERIFY(backend.requestDockByDesktopId(reference)); - QTRY_COMPARE(visible.rowCount(), 1); - QPointer presentation = visible.index(0, 0).data(dock::TaskManager::FolderPresentationRole).value(); - QVERIFY(presentation); - - QVERIFY(QMetaObject::invokeMethod(presentation, "rebind", Q_ARG(QString, "test://folder-renamed"))); - - const QString renamed = dock::FolderContentRegistry::reference("testsource", "test://folder-renamed"); - QTRY_COMPARE(settings->dockedElements(), QStringList{renamed}); - QTRY_COMPARE(visible.index(0, 0).data(dock::TaskManager::ItemIdRole).toString(), renamed); - QCOMPARE(visible.rowCount(), 1); - } - - // A deleted directory can never show contents again, so the pin has to be - // dropped instead of leaving a folder entry that stays permanently empty. - void contentPinDroppedWhenContentLost() - { - QCoreApplication::addLibraryPath(QStringLiteral(TEST_FOLDER_PLUGIN_DIR)); - dock::TaskManager backend; - auto settings = dock::TaskManagerSettings::instance(); - const QString survivor = dock::FolderContentRegistry::reference("unavailable", "keep-me"); - settings->setDockedElements({}); - QStandardItemModel apps, windows; - dock::DockCombineModel active(&windows, &apps, dock::TaskManager::DesktopIdRole, - [](QVariant, QAbstractItemModel *) { return QModelIndex(); }); - dock::DockGlobalElementModel global(&apps, &active); - dock::DockItemModel visible(&global); - - const QString reference = dock::FolderContentRegistry::reference("testsource", "test://folder"); - // An unavailable provider stands in for temporary unavailability; - // its pin must survive while the permanently lost pin disappears. - settings->setDockedElements({survivor}); - QVERIFY(backend.requestDockByDesktopId(reference)); - QTRY_COMPARE(visible.rowCount(), 2); - QPointer presentation; - for (int row = 0; row < visible.rowCount(); ++row) { - if (visible.index(row, 0).data(dock::TaskManager::ItemIdRole).toString() == reference) - presentation = visible.index(row, 0).data(dock::TaskManager::FolderPresentationRole).value(); - } - QVERIFY(presentation); - - QVERIFY(QMetaObject::invokeMethod(presentation, "lose")); - - // Only the lost pin goes away; an unavailable provider must not be - // mistaken for a deletion. - QTRY_COMPARE(settings->dockedElements(), QStringList{survivor}); - QTRY_COMPARE(visible.rowCount(), 1); - QCOMPARE(visible.index(0, 0).data(dock::TaskManager::ItemIdRole).toString(), survivor); - } - - void attachedPinningApi() - { - // No init()/load(): do not start a dock, window monitor or D-Bus service. - auto settings = dock::TaskManagerSettings::instance(); - settings->setDockedElements({}); - QStandardItemModel apps, windows; - ApplicationFolderModel folders; - dock::DockCombineModel active(&windows, &apps, dock::TaskManager::DesktopIdRole, - [](QVariant, QAbstractItemModel *) { return QModelIndex(); }); - dock::DockGlobalElementModel global(&apps, &active); - global.setApplicationFolderModel(&folders); - dock::TaskManager backend; - backend.m_dockGlobalElementModel = &global; - QQmlEngine engine; - engine.rootContext()->setContextProperty("_ds_applet", &backend); - QQmlComponent component(&engine); - component.setData(R"( - import QtQml - import FolderApiTest 1.0 - QtObject { - id: root - function dock(id) { return root.TestApplet.requestDockByDesktopId(id) } - function undock(id) { return TestApplet.requestUndockByDesktopId(id) } - } - )", QUrl()); - QScopedPointer object(component.create()); - QVERIFY2(object, qPrintable(component.errorString())); - const QString folderId = "internal/folders/1"; - QVariant result; - // A first pin must succeed through QML, so a later false result cannot - // be caused by an absent model or an unknown folder. - QVERIFY(QMetaObject::invokeMethod(object.get(), "dock", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, folderId))); - QCOMPARE(result, QVariant(true)); - QCOMPARE(settings->dockedElements(), QStringList{folderId}); - QCOMPARE(global.rowCount(), 1); - QVERIFY(backend.IsDocked(folderId)); - // Already docked: report false so the launcher drop is rejected and the - // existing pin is not reordered, but never append a duplicate entry. - QVERIFY(QMetaObject::invokeMethod(object.get(), "dock", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, folderId))); - QCOMPARE(result, QVariant(false)); - QCOMPARE(settings->dockedElements(), QStringList{folderId}); - QCOMPARE(global.rowCount(), 1); - QVERIFY(QMetaObject::invokeMethod(object.get(), "undock", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, folderId))); - QCOMPARE(result, QVariant(true)); - QVERIFY(!settings->isDocked(folderId)); - QVERIFY(!backend.IsDocked(folderId)); - QCOMPARE(global.rowCount(), 0); - QVERIFY(QMetaObject::invokeMethod(object.get(), "dock", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, folderId))); - QCOMPARE(result, QVariant(true)); - QCOMPARE(settings->dockedElements(), QStringList{folderId}); - QCOMPARE(global.rowCount(), 1); - // Reject reserved IDs without consulting the application manager. - QVERIFY(QMetaObject::invokeMethod(object.get(), "dock", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, "internal/invalid"))); - QCOMPARE(result, QVariant(false)); - } -}; - -int main(int argc, char **argv) -{ - QTemporaryDir config; - if (!config.isValid()) return 1; - // Isolate even constructor-time DConfig migration from the user's desktop. - qputenv("DSG_DCONFIG_BACKEND_TYPE", "FileBackend"); - qputenv("DSG_DCONFIG_FILE_BACKEND_LOCAL_PREFIX", config.path().toUtf8()); - qputenv("XDG_CONFIG_HOME", config.path().toUtf8()); - qputenv("DBUS_SESSION_BUS_ADDRESS", "unix:path=/nonexistent/folder-api-test-bus"); - QGuiApplication app(argc, argv); - qmlRegisterUncreatableType("FolderApiTest", 1, 0, "TestApplet", "Attached applet API only"); - TaskManagerQmlApiTest test; - return QTest::qExec(&test, argc, argv); -} -#include "taskmanagerqmlapitests.moc" diff --git a/tests/panels/dock/taskmanager/testfolderprovider.cpp b/tests/panels/dock/taskmanager/testfolderprovider.cpp deleted file mode 100644 index 5b06c7c04..000000000 --- a/tests/panels/dock/taskmanager/testfolderprovider.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later -#include "foldercontent.h" - -class TestPresentation : public dock::FolderPresentation -{ - Q_OBJECT -public: - using dock::FolderPresentation::FolderPresentation; - QString title() const override { return m_title; } - QVariantList previewIcons() const override { return {QUrl("image://icon/folder")}; } - Q_INVOKABLE void rename(const QString &title) { m_title = title; emit presentationChanged(); } - // Emulate a provider that resolved a new id for the same item, e.g. after - // the pinned directory was renamed on disk. - Q_INVOKABLE void rebind(const QString &id) { emit identityChanged(id); } - // Emulate a provider whose pinned directory was deleted on disk. - Q_INVOKABLE void lose() { emit contentLost(); } -private: - QString m_title = "Test folder"; -}; - -class TestFolderProvider : public QObject, public dock::FolderContentProvider -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID DS_FOLDER_CONTENT_PROVIDER_IID) - Q_INTERFACES(dock::FolderContentProvider) -public: - QString normalizeId(const QString &id) const override - { - if (id == "test://folder/") return QStringLiteral("test://folder"); - return id == "test://folder" || id == "test://folder-renamed" ? id : QString(); - } - dock::FolderPresentation *create(const QString &, QObject *parent) override { return new TestPresentation(parent); } -}; -#include "testfolderprovider.moc"