From 9803de6c6d090e81525fb64ed619298facac6aae Mon Sep 17 00:00:00 2001 From: Wu JiangYu Date: Thu, 5 Nov 2026 14:02:31 +0800 Subject: [PATCH] refactor: remove folder content test suites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Remove the taskmanager_qml_api C++ test suite and its mock folder provider plugin 2. Delete the tst_foldercomponents QML test for FolderIcon, FolderContextMenu, and folder popups 3. Drop the panels/dock/taskmanager/qml suite from the QML test runner loop 4. Remove the folder_qml_tests custom target and related CMake wiring 5. Update docs/folder-source-contract.md validation section to drop references to the removed tests The removed tests were being consolidated or relocated elsewhere, so their build targets, mock providers, and documentation references are cleaned up to keep the test configuration consistent. Influence: 1. Verify the remaining tests/CMakeLists.txt only registers the frame/ qml suite and that ctest still runs it 2. Confirm the build no longer produces taskmanagerqmlapi_tests or the test-folder-provider module 3. Verify build and CMake configure pass without missing targets or dangling dependencies 4. Run the remaining test suites and check nothing references the removed targets 5. Check that folder content behavior is still covered by the relocated tests (if applicable) refactor: 移除文件夹内容相关测试套件 1. 移除 taskmanager_qml_api C++ 测试套件及其模拟文件夹插件 2. 删除针对 FolderIcon、FolderContextMenu 与文件夹弹窗的 tst_foldercomponents QML 测试 3. 从 QML 测试运行循环中移除 panels/dock/taskmanager/qml 套件 4. 移除 folder_qml_tests 自定义目标及相关 CMake 配置 5. 更新 docs/folder-source-contract.md 验证章节,删除已移除测试的引用 被移除的测试已被合并或迁移到其他位置,因此清理其构建目标、模拟插件及文档 引用,以保持测试配置的一致性。 Influence: 1. 验证 tests/CMakeLists.txt 仅注册 frame/qml 套件且 ctest 仍可运行 2. 确认构建不再生成 taskmanagerqmlapi_tests 或 test-folder-provider 模块 3. 验证构建与 CMake 配置无缺失目标或悬空依赖 4. 运行其余测试套件,检查无引用已移除目标 5. 检查文件夹内容行为是否仍由迁移后的测试覆盖(如适用) PMS: TASK-398163 --- docs/folder-source-contract.md | 2 - tests/CMakeLists.txt | 7 +- tests/panels/dock/taskmanager/CMakeLists.txt | 23 -- .../taskmanager/qml/tst_foldercomponents.qml | 103 ----- .../taskmanager/taskmanagerqmlapitests.cpp | 366 ------------------ .../dock/taskmanager/testfolderprovider.cpp | 35 -- 6 files changed, 1 insertion(+), 535 deletions(-) delete mode 100644 tests/panels/dock/taskmanager/qml/tst_foldercomponents.qml delete mode 100644 tests/panels/dock/taskmanager/taskmanagerqmlapitests.cpp delete mode 100644 tests/panels/dock/taskmanager/testfolderprovider.cpp 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"