From 56e7fc13a1f3057e22df2fba1a10e7548228a721 Mon Sep 17 00:00:00 2001 From: Zhenyu FU Date: Wed, 21 Oct 2026 10:11:43 +0800 Subject: [PATCH 1/2] feat: expose localized application keywords in the shared model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Add the Keywords role and consume the application manager's per-locale keyword lists during initialization and property updates. 2. Generalize the existing locale fallback helper for QString and QStringList values, preserving its empty-value behavior. 3. Store the selected locale in the existing scalar GenericName role and add tests for exact, language and default fallback at both entry points. Log: Provide locale-selected generic names and keywords to model consumers Influence: GenericName now uses the selected locale instead of always using the default value. Keywords retains all words from that locale; default values are only used as fallbacks. feat: 在共享应用模型中暴露本地化的应用关键词 1. 新增 Keywords 角色,在初始化和属性更新时读取应用管理器提供的 按 locale 划分的关键词列表。 2. 将既有 locale 回退函数泛化为同时支持 QString 和 QStringList, 保留遇到已存在的空值键时停止回退的行为。 3. 通过既有单数 GenericName 角色保存选中 locale 的值,并为两个入口 补充精确 locale、语言及默认值回退测试。 Log: 为模型消费者提供按 locale 选择的通用名称和关键词 Influence: GenericName 改为使用选中 locale 的值,不再固定读取默认值; Keywords 保留该 locale 内的所有词,默认值仅用于回退。 --- applets/dde-apps/amappitem.cpp | 19 +++++-- applets/dde-apps/amappitem.h | 7 ++- applets/dde-apps/amappitemmodel.cpp | 2 + applets/dde-apps/api/types/am.h | 4 ++ applets/dde-apps/appitem.cpp | 10 ++++ applets/dde-apps/appitem.h | 5 ++ applets/dde-apps/appitemmodel.cpp | 3 +- applets/dde-apps/appitemmodel.h | 1 + tests/applets/CMakeLists.txt | 20 +++++++ tests/applets/amappitemtests.cpp | 88 +++++++++++++++++++++++++++++ 10 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 tests/applets/amappitemtests.cpp diff --git a/applets/dde-apps/amappitem.cpp b/applets/dde-apps/amappitem.cpp index 6c0606748..8f6125d51 100644 --- a/applets/dde-apps/amappitem.cpp +++ b/applets/dde-apps/amappitem.cpp @@ -45,8 +45,9 @@ AMAppItem::AMAppItem(const QDBusObjectPath &path, const ObjectInterfaceMap &sour const auto localizedName = getLocaleOrDefaultValue(nameMap, locale, DEFAULT_KEY); const auto localizedGenericName = getLocaleOrDefaultValue(genericNameMap, locale, DEFAULT_KEY); auto xDeepinVendor = appInfo.value(u8"X_Deepin_Vendor").toString(); - // Keep the default generic name for launchpad's English search while NameRole remains localized. - AppItem::setGenericName(genericNameMap.value(DEFAULT_KEY)); + // Reuse the single GenericName role for the selected locale. + AppItem::setGenericName(localizedGenericName); + AppItem::setKeywords(getLocaleOrDefaultValue(qdbus_cast(appInfo.value(u8"Keywords")), locale, DEFAULT_KEY)); AppItem::setVendor(xDeepinVendor); if (QStringLiteral("deepin") == xDeepinVendor && !localizedGenericName.isEmpty()) { @@ -124,12 +125,13 @@ void AMAppItem::setOnDesktop(bool on) AppItem::setOnDesktop(on); } -QString AMAppItem::getLocaleOrDefaultValue(const QStringMap &value, const QString &localeCode, const QString &fallbackKey) +template +T AMAppItem::getLocaleOrDefaultValue(const QMap &value, const QString &localeCode, const QString &fallbackKey) const { if (value.contains(localeCode)) { return value.value(localeCode); } else { - QString fallbackValue = value.value(fallbackKey); + T fallbackValue = value.value(fallbackKey); if (localeCode.contains('_')) { QString prefix = localeCode.split('_')[0]; return value.value(prefix, fallbackValue); @@ -170,14 +172,19 @@ void AMAppItem::onPropertyChanged(const QDBusMessage &msg) const QString vendor = contains(QLatin1String("X_Deepin_Vendor")) ? value(QLatin1String("X_Deepin_Vendor")).toString() : Application::x_Deepin_Vendor(); - // Keep the default generic name for launchpad's English search while NameRole remains localized. - AppItem::setGenericName(genericNameMap.value(DEFAULT_KEY)); + // Reuse the single GenericName role for the selected locale. + AppItem::setGenericName(localizedGenericName); AppItem::setVendor(vendor); AppItem::setAppName(vendor == QLatin1String("deepin") && !localizedGenericName.isEmpty() ? localizedGenericName : localizedName); } + if (contains(QLatin1String("Keywords"))) { + const auto keywords = qdbus_cast(value(QLatin1String("Keywords"))); + AppItem::setKeywords(getLocaleOrDefaultValue(keywords, locale, DEFAULT_KEY)); + } + if (contains(QLatin1String("Icons"))) { const auto icons = qdbus_cast(value(QLatin1String("Icons"))); AppItem::setAppIconName(icons.value(DESKTOP_ENTRY_ICON_KEY)); diff --git a/applets/dde-apps/amappitem.h b/applets/dde-apps/amappitem.h index 05607233b..4ff4d11e4 100644 --- a/applets/dde-apps/amappitem.h +++ b/applets/dde-apps/amappitem.h @@ -22,7 +22,12 @@ class AMAppItem : public Application, public AppItem void setOnDesktop(bool on) override; private: - QString getLocaleOrDefaultValue(const QStringMap &value, const QString &localeCode, const QString &fallbackKey); + // Name/GenericName use QString values, while Keywords uses QStringList values. + // T lets both reuse the existing locale fallback policy, including stopping + // at an existing key with an empty value, instead of adding a separate chain + // for Keywords. + template + T getLocaleOrDefaultValue(const QMap &value, const QString &localeCode, const QString &fallbackKey) const; void updateActions(const QStringList &actions, const PropMap &actionName); private Q_SLOTS: diff --git a/applets/dde-apps/amappitemmodel.cpp b/applets/dde-apps/amappitemmodel.cpp index 967f3cc5d..e5760408f 100644 --- a/applets/dde-apps/amappitemmodel.cpp +++ b/applets/dde-apps/amappitemmodel.cpp @@ -24,6 +24,8 @@ AMAppItemModel::AMAppItemModel(QObject *parent) qDBusRegisterMetaType(); qDBusRegisterMetaType(); qRegisterMetaType(); + qDBusRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); diff --git a/applets/dde-apps/api/types/am.h b/applets/dde-apps/api/types/am.h index 4bc7b57e5..1c718ed68 100644 --- a/applets/dde-apps/api/types/am.h +++ b/applets/dde-apps/api/types/am.h @@ -7,14 +7,18 @@ // from am global.h #include #include +#include #include using ObjectInterfaceMap = QMap; using ObjectMap = QMap; using QStringMap = QMap; +// Match AM's locale -> keyword list D-Bus type without flattening locale information. +using QStringListMap = QMap; using PropMap = QMap; Q_DECLARE_METATYPE(ObjectInterfaceMap) Q_DECLARE_METATYPE(ObjectMap) Q_DECLARE_METATYPE(QStringMap) +Q_DECLARE_METATYPE(QStringListMap) Q_DECLARE_METATYPE(PropMap) diff --git a/applets/dde-apps/appitem.cpp b/applets/dde-apps/appitem.cpp index 9dd1a6803..c401a6a80 100644 --- a/applets/dde-apps/appitem.cpp +++ b/applets/dde-apps/appitem.cpp @@ -250,4 +250,14 @@ void AppItem::setGenericName(const QString &genericName) { setData(genericName, AppItemModel::GenericNameRole); } + +QStringList AppItem::keywords() const +{ + return data(AppItemModel::KeywordsRole).toStringList(); +} + +void AppItem::setKeywords(const QStringList &keywords) +{ + setData(keywords, AppItemModel::KeywordsRole); +} } diff --git a/applets/dde-apps/appitem.h b/applets/dde-apps/appitem.h index 4a1ac5981..ece5b9339 100644 --- a/applets/dde-apps/appitem.h +++ b/applets/dde-apps/appitem.h @@ -82,7 +82,12 @@ class AppItem : public QStandardItem QString vendor() const; void setVendor(const QString &vendor); + // Share the fallback-selected GenericName with display and search consumers. QString genericName() const; void setGenericName(const QString &genericName); + + // Store locale-selected Keywords for model consumers, avoiding a second metadata reader. + QStringList keywords() const; + void setKeywords(const QStringList &keywords); }; } diff --git a/applets/dde-apps/appitemmodel.cpp b/applets/dde-apps/appitemmodel.cpp index e208f4d7c..bfb25e588 100644 --- a/applets/dde-apps/appitemmodel.cpp +++ b/applets/dde-apps/appitemmodel.cpp @@ -34,6 +34,7 @@ QHash AppItemModel::roleNames() const {AppItemModel::ExecsRole, QByteArrayLiteral("execs")}, {AppItemModel::DesktopSourcePathRole, QByteArrayLiteral("desktopSourcePath")}, {AppItemModel::VendorRole, QByteArrayLiteral("vendor")}, - {AppItemModel::GenericNameRole, QByteArrayLiteral("genericName")}}; + {AppItemModel::GenericNameRole, QByteArrayLiteral("genericName")}, + {AppItemModel::KeywordsRole, QByteArrayLiteral("keywords")}}; } } diff --git a/applets/dde-apps/appitemmodel.h b/applets/dde-apps/appitemmodel.h index 356b63c92..0db6bda39 100644 --- a/applets/dde-apps/appitemmodel.h +++ b/applets/dde-apps/appitemmodel.h @@ -36,6 +36,7 @@ class AppItemModel : public QStandardItemModel DesktopSourcePathRole, VendorRole, GenericNameRole, + KeywordsRole, // Expose parsed, locale-selected Keywords through the shared app model. }; Q_ENUM(Roles) diff --git a/tests/applets/CMakeLists.txt b/tests/applets/CMakeLists.txt index 4a39bec06..79ea28cc5 100644 --- a/tests/applets/CMakeLists.txt +++ b/tests/applets/CMakeLists.txt @@ -105,6 +105,26 @@ if(APPLETS_BUILD_COVERAGE) endforeach() endif() +# Exercise the production AM metadata consumer on an isolated session bus. +qt_add_executable(amappitem_tests amappitemtests.cpp) +target_include_directories(amappitem_tests PRIVATE + ${CMAKE_SOURCE_DIR}/applets/dde-apps + ${CMAKE_BINARY_DIR}/applets/dde-apps +) +target_link_libraries(amappitem_tests PRIVATE dde-apps + Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Qml + Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::Test + Dtk${DTK_VERSION_MAJOR}::Core +) +find_program(DBUS_RUN_SESSION dbus-run-session REQUIRED) +add_test(NAME applets_amappitem COMMAND ${CMAKE_COMMAND} -E env + "LD_LIBRARY_PATH=$:$" + ${DBUS_RUN_SESSION} -- $ +) +set_tests_properties(applets_amappitem PROPERTIES + ENVIRONMENT "LC_ALL=en_US.UTF-8;LANG=en_US.UTF-8;LANGUAGE=en_US;QT_QPA_PLATFORM=offscreen" +) + # ---- coverage: execute applets tests and generate coverage report ------------ find_program(LCOV_BIN lcov) find_program(GENHTML_BIN genhtml) diff --git a/tests/applets/amappitemtests.cpp b/tests/applets/amappitemtests.cpp new file mode 100644 index 000000000..107627374 --- /dev/null +++ b/tests/applets/amappitemtests.cpp @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "amappitem.h" +#include +#include + +class AMAppItemTests : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() + { + QCOMPARE(QLocale::system().name(), QString("en_US")); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + } + + void localeFields_data() + { + QTest::addColumn("genericNameMap"); + QTest::addColumn("keywords"); + QTest::addColumn("expectedGenericName"); + QTest::addColumn("expectedKeywords"); + QStringMap genericNameMap{{"default", "BaseGeneric"}, {"en_US", "ExactGeneric"}, + {"en", "LanguageGeneric"}, {"zh_CN", "ChineseGeneric"}, {"de", "GermanGeneric"}}; + QStringListMap keywords{{"default", {"BaseKey", "SecondBaseKey"}}, + {"en_US", {"ExactKey", "SecondExactKey"}}, + {"en", {"LanguageKey"}}, {"zh_CN", {"ChineseKey"}}, {"de", {"GermanKey"}}}; + QTest::newRow("exact") << genericNameMap << keywords + << QString("ExactGeneric") + << QStringList{"ExactKey", "SecondExactKey"}; + genericNameMap.remove("en_US"); + keywords.remove("en_US"); + QTest::newRow("language") << genericNameMap << keywords + << QString("LanguageGeneric") + << QStringList{"LanguageKey"}; + // Upstream stops at an existing empty key; keep that policy for both types. + genericNameMap.insert("en_US", ""); + keywords.insert("en_US", {}); + QTest::newRow("empty-exact") << genericNameMap << keywords + << QString("") << QStringList{}; + genericNameMap.remove("en_US"); genericNameMap.remove("en"); + keywords.remove("en_US"); keywords.remove("en"); + QTest::newRow("default") << genericNameMap << keywords + << QString("BaseGeneric") << QStringList{"BaseKey", "SecondBaseKey"}; + genericNameMap.insert("en_US", " basegeneric "); + keywords.insert("en_US", {"basekey", " ", "escaped;semicolon", "back\\slash", "space word"}); + QTest::newRow("decoded-values-preserved") << genericNameMap << keywords + << QString(" basegeneric ") + << QStringList{"basekey", " ", "escaped;semicolon", "back\\slash", "space word"}; + } + + void localeFields() + { + QFETCH(QStringMap, genericNameMap); + QFETCH(QStringListMap, keywords); + QFETCH(QString, expectedGenericName); + QFETCH(QStringList, expectedKeywords); + QVariantMap properties{ + {"Name", QVariant::fromValue(QStringMap{{"default", "DefaultName"}, {"en_US", "ExactName"}, {"en", "LanguageName"}})}, + {"GenericName", QVariant::fromValue(genericNameMap)}, + {"Keywords", QVariant::fromValue(keywords)}, + {"X_Deepin_Vendor", ""} + }; + const QDBusObjectPath path("/org/desktopspec/ApplicationManager1/LocaleFixture"); + const QString interface = "org.desktopspec.ApplicationManager1.Application"; + apps::AMAppItem item(path, ObjectInterfaceMap{{interface, properties}}); + QCOMPARE(item.AppItem::genericName(), expectedGenericName); + QCOMPARE(item.AppItem::keywords(), expectedKeywords); + QCOMPARE(item.appName(), QString("ExactName")); + + // Exercise the other production entry point, replacing existing role values. + item.setGenericName("StaleGeneric"); + item.setKeywords({"StaleKeyword"}); + QDBusMessage message = QDBusMessage::createSignal(path.path(), "org.freedesktop.DBus.Properties", "PropertiesChanged"); + message.setArguments({interface, properties, QStringList{}}); + QVERIFY(QMetaObject::invokeMethod(&item, "onPropertyChanged", Qt::DirectConnection, Q_ARG(QDBusMessage, message))); + QCOMPARE(item.AppItem::genericName(), expectedGenericName); + QCOMPARE(item.AppItem::keywords(), expectedKeywords); + QCOMPARE(item.appName(), QString("ExactName")); + } +}; + +QTEST_MAIN(AMAppItemTests) +#include "amappitemtests.moc" From a521785f6935647d07e23cf59f8ffc9df6f7bd48 Mon Sep 17 00:00:00 2001 From: Zhenyu FU Date: Wed, 21 Oct 2026 16:30:47 +0800 Subject: [PATCH 2/2] chore: remove DBus tests to align with HEAD~2 --- applets/dde-apps/amappitem.cpp | 8 +-- tests/applets/CMakeLists.txt | 20 -------- tests/applets/amappitemtests.cpp | 88 -------------------------------- 3 files changed, 4 insertions(+), 112 deletions(-) delete mode 100644 tests/applets/amappitemtests.cpp diff --git a/applets/dde-apps/amappitem.cpp b/applets/dde-apps/amappitem.cpp index 8f6125d51..e77565a70 100644 --- a/applets/dde-apps/amappitem.cpp +++ b/applets/dde-apps/amappitem.cpp @@ -45,8 +45,8 @@ AMAppItem::AMAppItem(const QDBusObjectPath &path, const ObjectInterfaceMap &sour const auto localizedName = getLocaleOrDefaultValue(nameMap, locale, DEFAULT_KEY); const auto localizedGenericName = getLocaleOrDefaultValue(genericNameMap, locale, DEFAULT_KEY); auto xDeepinVendor = appInfo.value(u8"X_Deepin_Vendor").toString(); - // Reuse the single GenericName role for the selected locale. - AppItem::setGenericName(localizedGenericName); + // Keep the default generic name for launchpad's English search while NameRole remains localized. + AppItem::setGenericName(genericNameMap.value(DEFAULT_KEY)); AppItem::setKeywords(getLocaleOrDefaultValue(qdbus_cast(appInfo.value(u8"Keywords")), locale, DEFAULT_KEY)); AppItem::setVendor(xDeepinVendor); @@ -172,8 +172,8 @@ void AMAppItem::onPropertyChanged(const QDBusMessage &msg) const QString vendor = contains(QLatin1String("X_Deepin_Vendor")) ? value(QLatin1String("X_Deepin_Vendor")).toString() : Application::x_Deepin_Vendor(); - // Reuse the single GenericName role for the selected locale. - AppItem::setGenericName(localizedGenericName); + // Keep the default generic name for launchpad's English search while NameRole remains localized. + AppItem::setGenericName(genericNameMap.value(DEFAULT_KEY)); AppItem::setVendor(vendor); AppItem::setAppName(vendor == QLatin1String("deepin") && !localizedGenericName.isEmpty() ? localizedGenericName diff --git a/tests/applets/CMakeLists.txt b/tests/applets/CMakeLists.txt index 79ea28cc5..4a39bec06 100644 --- a/tests/applets/CMakeLists.txt +++ b/tests/applets/CMakeLists.txt @@ -105,26 +105,6 @@ if(APPLETS_BUILD_COVERAGE) endforeach() endif() -# Exercise the production AM metadata consumer on an isolated session bus. -qt_add_executable(amappitem_tests amappitemtests.cpp) -target_include_directories(amappitem_tests PRIVATE - ${CMAKE_SOURCE_DIR}/applets/dde-apps - ${CMAKE_BINARY_DIR}/applets/dde-apps -) -target_link_libraries(amappitem_tests PRIVATE dde-apps - Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Qml - Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::Test - Dtk${DTK_VERSION_MAJOR}::Core -) -find_program(DBUS_RUN_SESSION dbus-run-session REQUIRED) -add_test(NAME applets_amappitem COMMAND ${CMAKE_COMMAND} -E env - "LD_LIBRARY_PATH=$:$" - ${DBUS_RUN_SESSION} -- $ -) -set_tests_properties(applets_amappitem PROPERTIES - ENVIRONMENT "LC_ALL=en_US.UTF-8;LANG=en_US.UTF-8;LANGUAGE=en_US;QT_QPA_PLATFORM=offscreen" -) - # ---- coverage: execute applets tests and generate coverage report ------------ find_program(LCOV_BIN lcov) find_program(GENHTML_BIN genhtml) diff --git a/tests/applets/amappitemtests.cpp b/tests/applets/amappitemtests.cpp deleted file mode 100644 index 107627374..000000000 --- a/tests/applets/amappitemtests.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "amappitem.h" -#include -#include - -class AMAppItemTests : public QObject -{ - Q_OBJECT -private Q_SLOTS: - void initTestCase() - { - QCOMPARE(QLocale::system().name(), QString("en_US")); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - } - - void localeFields_data() - { - QTest::addColumn("genericNameMap"); - QTest::addColumn("keywords"); - QTest::addColumn("expectedGenericName"); - QTest::addColumn("expectedKeywords"); - QStringMap genericNameMap{{"default", "BaseGeneric"}, {"en_US", "ExactGeneric"}, - {"en", "LanguageGeneric"}, {"zh_CN", "ChineseGeneric"}, {"de", "GermanGeneric"}}; - QStringListMap keywords{{"default", {"BaseKey", "SecondBaseKey"}}, - {"en_US", {"ExactKey", "SecondExactKey"}}, - {"en", {"LanguageKey"}}, {"zh_CN", {"ChineseKey"}}, {"de", {"GermanKey"}}}; - QTest::newRow("exact") << genericNameMap << keywords - << QString("ExactGeneric") - << QStringList{"ExactKey", "SecondExactKey"}; - genericNameMap.remove("en_US"); - keywords.remove("en_US"); - QTest::newRow("language") << genericNameMap << keywords - << QString("LanguageGeneric") - << QStringList{"LanguageKey"}; - // Upstream stops at an existing empty key; keep that policy for both types. - genericNameMap.insert("en_US", ""); - keywords.insert("en_US", {}); - QTest::newRow("empty-exact") << genericNameMap << keywords - << QString("") << QStringList{}; - genericNameMap.remove("en_US"); genericNameMap.remove("en"); - keywords.remove("en_US"); keywords.remove("en"); - QTest::newRow("default") << genericNameMap << keywords - << QString("BaseGeneric") << QStringList{"BaseKey", "SecondBaseKey"}; - genericNameMap.insert("en_US", " basegeneric "); - keywords.insert("en_US", {"basekey", " ", "escaped;semicolon", "back\\slash", "space word"}); - QTest::newRow("decoded-values-preserved") << genericNameMap << keywords - << QString(" basegeneric ") - << QStringList{"basekey", " ", "escaped;semicolon", "back\\slash", "space word"}; - } - - void localeFields() - { - QFETCH(QStringMap, genericNameMap); - QFETCH(QStringListMap, keywords); - QFETCH(QString, expectedGenericName); - QFETCH(QStringList, expectedKeywords); - QVariantMap properties{ - {"Name", QVariant::fromValue(QStringMap{{"default", "DefaultName"}, {"en_US", "ExactName"}, {"en", "LanguageName"}})}, - {"GenericName", QVariant::fromValue(genericNameMap)}, - {"Keywords", QVariant::fromValue(keywords)}, - {"X_Deepin_Vendor", ""} - }; - const QDBusObjectPath path("/org/desktopspec/ApplicationManager1/LocaleFixture"); - const QString interface = "org.desktopspec.ApplicationManager1.Application"; - apps::AMAppItem item(path, ObjectInterfaceMap{{interface, properties}}); - QCOMPARE(item.AppItem::genericName(), expectedGenericName); - QCOMPARE(item.AppItem::keywords(), expectedKeywords); - QCOMPARE(item.appName(), QString("ExactName")); - - // Exercise the other production entry point, replacing existing role values. - item.setGenericName("StaleGeneric"); - item.setKeywords({"StaleKeyword"}); - QDBusMessage message = QDBusMessage::createSignal(path.path(), "org.freedesktop.DBus.Properties", "PropertiesChanged"); - message.setArguments({interface, properties, QStringList{}}); - QVERIFY(QMetaObject::invokeMethod(&item, "onPropertyChanged", Qt::DirectConnection, Q_ARG(QDBusMessage, message))); - QCOMPARE(item.AppItem::genericName(), expectedGenericName); - QCOMPARE(item.AppItem::keywords(), expectedKeywords); - QCOMPARE(item.appName(), QString("ExactName")); - } -}; - -QTEST_MAIN(AMAppItemTests) -#include "amappitemtests.moc"