diff --git a/.reuse/dep5 b/.reuse/dep5 index 5b3252a..cbfe56a 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -32,3 +32,8 @@ License: CC0-1.0 Files: rpm/* debian/* archlinux/* Copyright: None License: CC0-1.0 + +# test +Files: tests/data/* +Copyright: None +License: CC0-1.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index d43ccc9..d2b9d19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,40 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Qt6 REQUIRED COMPONENTS Core DBus Concurrent) find_package(Threads REQUIRED) +qt_add_dbus_adaptor(ApplicationManagerSource ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ApplicationManager1.xml applicationmanager1service.h ApplicationManager1Service) +add_library(ApplicationManager OBJECT ${ApplicationManagerSource}) +qt_add_dbus_adaptor(ApplicationSource ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ApplicationManager1.Application.xml applicationservice.h ApplicationService) +add_library(Application OBJECT ${ApplicationSource}) +qt_add_dbus_adaptor(InstnaceSource ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml instanceservice.h InstanceService) +add_library(Instance OBJECT ${InstnaceSource}) +qt_add_dbus_adaptor(JobManagerSource ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.JobManager1.xml jobmanager1service.h JobManager1Service) +add_library(JobManager OBJECT ${JobManagerSource}) +qt_add_dbus_adaptor(JobSource ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.JobManager1.Job.xml jobservice.h JobService) +add_library(Job OBJECT ${JobSource}) + +set(AdaptorLib) +list(APPEND AdaptorLib ApplicationManager Application Instance JobManager Job) + +foreach(obj IN LISTS AdaptorLib) + target_link_libraries(${obj} PUBLIC + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::Concurrent + ) + + target_include_directories(${obj} PUBLIC + ${PROJECT_SOURCE_DIR}/src/include + ${PROJECT_SOURCE_DIR}/src/dbus + ) +endforeach() + add_subdirectory(src) # add_subdirectory(docs) -# add_subdirectory(tests) # add_subdirectory(plugin) + +include(CTest) + +if(BUILD_TESTING) + enable_testing() + add_subdirectory(tests) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3535808..6dae734 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,31 +1,26 @@ include(GNUInstallDirs) set(BIN_NAME dde-application-manager) +set(LIB_NAME ddeam) -set(DBUS_INTERFACE_DIR ${CMAKE_CURRENT_LIST_DIR}/dbus) +file(GLOB_RECURSE SRCS ${CMAKE_CURRENT_LIST_DIR}/*.cpp) -set(DBUSADAPTORS "") -file(GLOB_RECURSE SRCS ${CMAKE_CURRENT_LIST_DIR}/*.cpp ${CMAKE_CURRENT_LIST_DIR}/*.h) +list(REMOVE_ITEM SRCS "${PROJECT_SOURCE_DIR}/src/utils.cpp") -qt_add_dbus_adaptor(DBUSADAPTORS ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ApplicationManager1.xml applicationmanager1service.h ApplicationManager1Service) -qt_add_dbus_adaptor(DBUSADAPTORS ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ApplicationManager1.Application.xml applicationservice.h ApplicationService) -qt_add_dbus_adaptor(DBUSADAPTORS ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml instanceservice.h InstanceService) -qt_add_dbus_adaptor(DBUSADAPTORS ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.JobManager1.xml jobmanager1service.h JobManager1Service) -qt_add_dbus_adaptor(DBUSADAPTORS ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.JobManager1.Job.xml jobservice.h JobService) +add_library(${LIB_NAME} ${SRCS}) -add_executable(${BIN_NAME} ${DBUSADAPTORS} ${SRCS}) - -target_include_directories(${BIN_NAME} PRIVATE - ${CMAKE_CURRENT_LIST_DIR}/include - ${CMAKE_CURRENT_LIST_DIR}/dbus - ${CMAKE_CURRENT_BINARY_DIR}/src +target_include_directories(${LIB_NAME} PRIVATE + ${PROJECT_BINARY_DIR} ) -target_link_libraries(${BIN_NAME} PRIVATE - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::DBus - Qt${QT_VERSION_MAJOR}::Concurrent +target_link_libraries(${LIB_NAME} PUBLIC Threads::Threads + ${AdaptorLib} +) + +add_executable(${BIN_NAME} main.cpp utils.cpp) +target_link_libraries(${BIN_NAME} PRIVATE + ${LIB_NAME} ) install(TARGETS ${BIN_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index 356d0f5..97432fc 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later #include "applicationmanager1service.h" -#include "applicationmanager1adaptor.h" #include "applicationadaptor.h" #include "global.h" @@ -46,7 +45,7 @@ QDBusObjectPath ApplicationManager1Service::Launch(const QString &id, objectPath.prepend(DDEApplicationManager1ApplicationObjectPath); QSharedPointer app{new ApplicationService{id}}; auto *ptr = app.data(); - if (registerObjectToDbus(ptr, objectPath, getDBusInterface())) { + if (registerObjectToDbus(new ApplicationAdaptor(ptr), objectPath, getDBusInterface())) { QDBusObjectPath path{objectPath}; m_applicationList.insert(path, app); return path; diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index eb62659..e95756c 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "applicationservice.h" +#include "applicationadaptor.h" #include "instanceadaptor.h" #include @@ -27,7 +28,7 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL QString objectPath{m_applicationPath.path() + "/" + QUuid::createUuid().toString()}; QSharedPointer ins{new InstanceService{objectPath, ""}}; auto *ptr = ins.data(); - if (registerObjectToDbus(ptr, objectPath, getDBusInterface())) { + if (registerObjectToDbus(new InstanceAdaptor(ptr), objectPath, getDBusInterface())) { m_Instances.insert(QDBusObjectPath{objectPath}, ins); return QDBusObjectPath{objectPath}; } diff --git a/src/dbus/jobmanager1service.h b/src/dbus/jobmanager1service.h index 2c06556..943e82e 100644 --- a/src/dbus/jobmanager1service.h +++ b/src/dbus/jobmanager1service.h @@ -33,9 +33,9 @@ public: { static_assert(std::is_invocable_v, "param type must be QVariant."); - QString objectPath{DDEApplicationManager1JobObjectPath + QUuid::createUuid().toString()}; - QFuture future = QtConcurrent::mappedReduced( - args.begin(), args.end(), func, &QVariantList::insert, QVariantList{}, QtConcurrent::ReduceOption::OrderedReduce); + QString objectPath{DDEApplicationManager1JobObjectPath + QUuid::createUuid().toString(QUuid::Id128)}; + auto future = QtConcurrent::mappedReduced( + args.begin(), args.end(), func,qOverload(&QVariantList::append), QVariantList{}, QtConcurrent::ReduceOption::OrderedReduce); QSharedPointer job{new JobService{future}}; auto path = QDBusObjectPath{objectPath}; { @@ -43,8 +43,8 @@ public: m_jobs.insert(path, job); // Insertion is always successful } emit JobNew(path, source); - registerObjectToDbus(job.data(), objectPath, getDBusInterface()); - auto emitRemove = [this, job, path, future] { + registerObjectToDbus(new JobAdaptor(job.data()), objectPath, getDBusInterface()); + auto emitRemove = [this, job, path, future] (QVariantList value) { decltype(m_jobs)::size_type removeCount{0}; { QMutexLocker locker{&m_mutex}; @@ -52,20 +52,21 @@ public: } // removeCount means m_jobs can't find value which corresponding with path // and we shouldn't emit jobRemoved signal because this signal may already has been emit - if (removeCount == 0) { + if (removeCount == 0) { qCritical() << "Job already has been removed: " << path.path(); - return; + return value; } QString result{job->status()}; for (const auto &val : future.result()) { - if (val.canConvert()) { + if (val.template canConvert()) { result = "failed"; } break; } emit this->JobRemoved(path, result, future.result()); + return value; }; - future.then(QtFuture::Launch::Sync, emitRemove); + future.then(emitRemove); } Q_SIGNALS: diff --git a/src/demo.cpp b/src/demo.cpp deleted file mode 100644 index c2df875..0000000 --- a/src/demo.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "demo.h" -#include -#include - -void greet() -{ - std::cout << QString{"Hello"}.toStdString() < DesktopFile::searchDesktopFile(const QString &desktop auto components = path.split(QDir::separator()).toList(); auto it = std::find(components.cbegin(), components.cend(), "applications"); if (it == components.cend()) { - qWarning() << "fatal error: file location invalid"; - err = ParseError::InvalidLocation; - return std::nullopt; + qWarning() << "custom location detected, Id wouldn't be generated."; + } else { + QString FileId; + ++it; + while (it != components.cend()) + FileId += (*(it++) + "-"); + id = FileId.chopped(1); } - QString FileId; - ++it; - while (it != components.cend()) - FileId += (*(it++) + "-"); - id = FileId.chopped(1); - err = ParseError::NoError; - return DesktopFile{path,id}; + return DesktopFile{std::move(path),std::move(id)}; } ParseError DesktopEntry::parse(QTextStream& stream) noexcept @@ -239,13 +237,16 @@ QString DesktopEntry::Value::toIconString(bool &ok) const noexcept bool DesktopEntry::Value::toBoolean(bool &ok) const noexcept { - ok = true; - const auto& str = (*this)[defaultKeyStr]; - if (str.compare("true")) - return true; - if (str.compare("false")) - return false; ok = false; + const auto& str = (*this)[defaultKeyStr]; + if (str == "true") { + ok = true; + return true; + } + if (str == "false") { + ok = true; + return false; + } return false; } @@ -262,3 +263,41 @@ QDebug operator<<(QDebug debug, const DesktopEntry::Value &v) debug << static_cast&>(v); return debug; } + +QDebug operator<<(QDebug debug, const ParseError &v) +{ + QDebugStateSaver saver{debug}; + QString errMsg; + switch (v) { + case ParseError::NoError:{ + errMsg = "no error."; + break; + } + case ParseError::NotFound:{ + errMsg = "file not found."; + break; + } + case ParseError::MismatchedFile:{ + errMsg = "file type is mismatched."; + break; + } + case ParseError::InvalidLocation:{ + errMsg = "file location is invalid, please check $XDG_DATA_DIRS."; + break; + } + case ParseError::OpenFailed:{ + errMsg = "couldn't open the file."; + break; + } + case ParseError::GroupHeaderInvalid:{ + errMsg = "groupHead syntax is invalid."; + break; + } + case ParseError::EntryKeyInvalid:{ + errMsg = "key syntax is invalid."; + break; + } + } + debug << errMsg; + return debug; +} diff --git a/src/include/demo.h b/src/include/demo.h deleted file mode 100644 index 8b067a8..0000000 --- a/src/include/demo.h +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -void greet(); diff --git a/src/include/desktopentry.h b/src/include/desktopentry.h index e76861c..7aef25f 100644 --- a/src/include/desktopentry.h +++ b/src/include/desktopentry.h @@ -14,7 +14,6 @@ constexpr static auto defaultKeyStr = "default"; enum class ParseError { NoError, NotFound, - FilePathEmpty, MismatchedFile, InvalidLocation, OpenFailed, @@ -37,13 +36,13 @@ public: friend QDebug operator<<(QDebug debug, const DesktopEntry::Value &v); private: - QString unescape(const QString& str) const noexcept; + [[nodiscard]] QString unescape(const QString &str) const noexcept; }; DesktopEntry() = default; ~DesktopEntry() = default; - ParseError parse(QTextStream& stream) noexcept; - QMap group(const QString &key) const noexcept; + [[nodiscard]] ParseError parse(QTextStream& stream) noexcept; + [[nodiscard]] QMap group(const QString &key) const noexcept; private: QMap> m_entryMap; @@ -54,13 +53,23 @@ private: struct DesktopFile { - const QString filePath; - const QString desktopId; + DesktopFile(const DesktopFile &) = default; + DesktopFile(DesktopFile &&) = default; + DesktopFile &operator=(const DesktopFile &) = default; + DesktopFile &operator=(DesktopFile &&) = default; + ~DesktopFile() = default; + const QString &filePath() const { return m_filePath; } + const QString &desktopId() const { return m_desktopId; } + static std::optional searchDesktopFile(const QString &desktopFilePath, ParseError& err) noexcept; private: - DesktopFile() = default; + DesktopFile(QString &&path,QString &&fileId):m_filePath(std::move(path)),m_desktopId(std::move(fileId)){} + QString m_filePath; + QString m_desktopId; }; QDebug operator<<(QDebug debug, const DesktopEntry::Value& v); + +QDebug operator<<(QDebug debug, const ParseError &v); diff --git a/src/include/global.h b/src/include/global.h index e31d2c9..5aa5214 100644 --- a/src/include/global.h +++ b/src/include/global.h @@ -52,21 +52,7 @@ private: QString m_busAddress; }; -template -bool registerObjectToDbus(T parent, const QString &path, const QString &interface) -{ - using service_type = std::remove_const_t; - static_assert(std::is_pointer_v, "param type must be a pointer"); - static_assert(std::is_base_of_v> and - std::is_base_of_v, - "param type must derive QObject"); - auto &con = ApplicationManager1DBus::instance().CustomBus(); - if (!con.registerObject(path, interface, new U{parent})) { - qCritical() << "register object failed:" << path << interface << con.lastError(); - return false; - } - return true; -} +bool registerObjectToDbus(QObject* o, const QString &path, const QString &interface); template QString getDBusInterface() diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..905869d --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..b954c28 --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,11 @@ +#include "global.h" + +bool registerObjectToDbus(QObject *o, const QString &path, const QString &interface) +{ + auto &con = ApplicationManager1DBus::instance().CustomBus(); + if (!con.registerObject(path, interface, o)) { + qCritical() << "register object failed:" << path << interface << con.lastError(); + return false; + } + return true; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..0e76aac --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,39 @@ +set(BIN_NAME "ut-ddeam") + +include(FindGTest) +find_package(GTest REQUIRED) + +add_compile_definitions(DDEAM_UNIT_TESTING) + +file(GLOB_RECURSE SRCS ${PROJECT_SOURCE_DIR}/src/*.cpp) +file(GLOB_RECURSE TESTS ${CMAKE_CURRENT_LIST_DIR}/*.cpp) + +list(REMOVE_ITEM SRCS "${PROJECT_SOURCE_DIR}/src/main.cpp") +list(REMOVE_ITEM SRCS "${PROJECT_SOURCE_DIR}/src/utils.cpp") + +add_executable(${BIN_NAME} ${SRCS} ${TESTS}) + +target_include_directories(${BIN_NAME} PRIVATE + ${PROJECT_BINARY_DIR}/ +) + +target_link_libraries(${BIN_NAME} PRIVATE + GTest::gtest + ${AdaptorLib} +) + +target_compile_options(${BIN_NAME} PRIVATE + -fsanitize=undefined + -fsanitize=address +) + +target_link_options(${BIN_NAME} PRIVATE + -fsanitize=undefined + -fsanitize=address +) + +add_test( + NAME UnitTest + COMMAND ${BIN_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) diff --git a/tests/data/desktopExample.desktop b/tests/data/desktopExample.desktop new file mode 100644 index 0000000..e8ae088 --- /dev/null +++ b/tests/data/desktopExample.desktop @@ -0,0 +1,110 @@ +[Desktop Entry] +Categories=Utility;TextEditor; +Comment=Simple and easy to use text editor +Exec=deepin-editor %F +Icon=deepin-editor +Name=Text Editor +GenericName=Text Editor +StartupNotify=false +Type=Application +X-Deepin-AppID=deepin-editor +X-MultipleArgs=false +X-Deepin-CreatedBy=com.deepin.dde.daemon.Launcher +X-Deepin-Vendor=deepin +# Translations: +# Do not manually modify! +Comment[ar]=محرر النصوص بسيط وسهل الاستخدام +Comment[bo]=སྟབས་བདེ་ལ་སྤྱོད་བདེ་བའི་ཡིག་ཆ་རྩོམ་སྒྲིག་ཆས། +Comment[br]=An aozer testennoù simpl hag aes d'ober gantañ +Comment[ca]=Editor de text simple i fàcil d'usar +Comment[cs]=Jednoduchý a snadno se používající textový editor +Comment[da]=Simpel og letanvendelig teksteditor +Comment[de]=Einfacher, leicht zu bedienender Texteditor +Comment[es]=Editor de texto simple y fácil de usar +Comment[et]=Lihtne ja kergesti kasutatav tekstiredaktor +Comment[fi]=Yksinkertainen ja helppokäyttöinen tekstieditori +Comment[fr]=Éditeur de texte simple et facile à utiliser +Comment[gl_ES]=Editor de texto sinxelo e fácil de usar +Comment[hr]=Jednostavan i lagan za korištenje uređivač teksta +Comment[hu]=Letisztult és könnyen használható szövegszerkesztő +Comment[it]=Editor di testo semplice e facile da usare. Localizzazione italiana a cura di Massimo A. Carofano. +Comment[ko]=단순하고 사용하기 쉬운 텍스트 편집기 +Comment[lt]=Paprastas ir lengvas naudoti tekstų redaktorius +Comment[ms]=Penyunting teks yang ringkas dan mudah digunakan +Comment[nl]=Eenvoudig te gebruiken tekstbewerker +Comment[pl]=Prosty i łatwy w użyciu edytor tekstu +Comment[pt]=Editor de texto simples e fácil de usar +Comment[pt_BR]=Um editor de texto simples e fácil de usar +Comment[ru]=Простой и удобный текстовый редактор +Comment[sq]=Përpunues tekstesh i thjeshtë dhe i kollajtë për t’u përdorur +Comment[sr]=Уењђивач текста који је једноставан за употребу +Comment[tr]=Basit ve kullanımı kolay metin düzenleyici +Comment[ug]=ئاددىي، قوللىنىشچان تېكىست تەھرىرلىگۈچ +Comment[uk]=Простий і доступний текстовий редактор +Comment[zh_CN]=简单好用的文本编辑器 +Comment[zh_HK]=簡單好用的文本編輯器 +Comment[zh_TW]=簡單好用的文字編輯器 +GenericName[ar]=محرر النصوص +GenericName[bo]=ཡིག་ཆ་རྩོམ་སྒྲུག་ཆས། +GenericName[br]=Aozer testennoù +GenericName[ca]=Editor de text +GenericName[cs]=Textový editor +GenericName[da]=Teksteditor +GenericName[de]=Text Editor +GenericName[es]=Editor de texto +GenericName[et]=Tekstiredaktor +GenericName[fi]=Tekstieditori +GenericName[fr]=Éditeur de texte +GenericName[en_US.UTF-8@euro;collation=traditional]=just for test\;teststing=abab\; +GenericName[gl_ES]=Editor de texto +GenericName[hr]=Uređivač teksta +GenericName[hu]=Szövegszerkesztő +GenericName[it]=Editor di Testo +GenericName[ko]=텍스트 편집기 +GenericName[lt]=Tekstų redaktorius +GenericName[ms]=Penyunting Teks +GenericName[nl]=Tekstbewerker +GenericName[pl]=Edytor tekstu +GenericName[pt]=Editor de texto +GenericName[pt_BR]=Editor de Textos +GenericName[ru]=Текстовый редактор +GenericName[sq]=Përpunues Tekstesh +GenericName[sr]=Уређивач Текста +GenericName[tr]=Metin Düzenleyici +GenericName[ug]=تېكىست تەھرىرلىگۈچ +GenericName[uk]=Текстовий редактор +GenericName[zh_CN]=文本编辑器 +GenericName[zh_HK]=文本編輯器 +GenericName[zh_TW]=文字編輯器 +MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-patch;text/x-adasrc;text/x-chdr;text/x-csrc;text/css;application/x-desktop;text/x-patch;text/x-fortran;text/html;text/x-java;text/x-tex;text/x-makefile;text/x-objcsrc;text/x-pascal;application/x-perl;application/x-perl;application/x-php;text/vnd.wap.wml;text/x-python;application/x-ruby;text/sgml;application/xml;model/vrml;image/svg+xml;application/json; +Name[ar]=محرر نصوص ديبين +Name[bo]=གཏིང་ཟབ་ཡིག་ཆ་རྩོམ་སྒྲིག་ཆས། +Name[br]=Aozer testennoù Deepin +Name[ca]=Editor de text del Deepin +Name[cs]=Deepin textový editor +Name[da]=Deepin teksteditor +Name[de@euro]=Deepin Text Editor +Name[es]=Editor de texto +Name[et]=Deepin tekstiredaktor +Name[fi]=Deepin tekstieditori +Name[fr]=Éditeur de texte Deepin +Name[gl_ES]=Editor de texto Deepin +Name[hr]=Deepin uređivač teksta +Name[hu]=Deepin® Szövegszerkesztő +Name[it]=Editor di Testo di Deepin +Name[ko]=Deepin 텍스트 편집기 +Name[lt]=Deepin tekstų redaktorius +Name[ms]=Penyunting Teks Deepin +Name[nl]=Deepin Tekstbewerker +Name[pl]=Edytor Tekstu Deepin +Name[pt]=Editor de texto Deepin +Name[pt_BR]=deepin Editor de Textos +Name[ru]=Текстовый Редактор Deepin +Name[sq]=Përpunues Tekstesh Deepin +Name[sr]=Дипин Уређивач Текста +Name[tr]=Deepin Metin Düzenleyici +Name[ug]=Deepin تېكىست تەھرىرلىگۈچ +Name[uk]=Текстовий редактор Deepin +Name[zh_CN]=文本编辑器 +Name[zh_HK]=Deepin 文本編輯器 +Name[zh_TW]=Deepin 文字編輯器 diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..96a2e4d --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + int ret{0}; + QTimer::singleShot(0, &app, [&ret] { + ret = RUN_ALL_TESTS(); + QCoreApplication::quit(); + }); + __sanitizer_set_report_path("asan_am.log"); + QCoreApplication::exec(); + return ret; +} diff --git a/tests/ut_desktopentry.cpp b/tests/ut_desktopentry.cpp new file mode 100644 index 0000000..a353bbe --- /dev/null +++ b/tests/ut_desktopentry.cpp @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "desktopentry.h" +#include +#include +#include +#include +#include +#include + +class TestDesktopEntry : public testing::Test +{ +public: + static void SetUpTestCase() + { + auto curDir = QDir::current(); + QString path{curDir.absolutePath() + "/data/desktopExample.desktop"}; + ParseError err; + auto file = DesktopFile::searchDesktopFile(path,err); + if (!file.has_value()) { + qWarning() << "search " << path << "failed:" << err; + return; + } + m_file.reset(new DesktopFile{std::move(file).value()}); + } + void SetUp() override + { + + } + void TearDown() override {} + QSharedPointer file() { return m_file; } +private: + static inline QSharedPointer m_file; +}; + +TEST_F(TestDesktopEntry, desktopFile) +{ + const auto& fileptr = file(); + ASSERT_FALSE(fileptr.isNull()); + const auto &exampleFile = file(); + auto curDir = QDir::current(); + QString path{curDir.absolutePath() + "/data/desktopExample.desktop"}; + EXPECT_EQ(exampleFile->filePath().toStdString(), path.toStdString()); + EXPECT_EQ(exampleFile->desktopId().toStdString(), ""); +} + +TEST_F(TestDesktopEntry, prase) +{ + const auto &exampleFile = file(); + ASSERT_FALSE(exampleFile.isNull());; + DesktopEntry entry; + QFile in{exampleFile->filePath()}; + ASSERT_TRUE(in.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)); + QTextStream fs{&in}; + auto err = entry.parse(fs); + ASSERT_EQ(err, ParseError::NoError); + + auto group = entry.group("Desktop Entry"); + ASSERT_FALSE(group.isEmpty()); + + auto name = group.constFind("Name"); + ASSERT_NE(name, group.cend()); + + bool ok; + name->toBoolean(ok); + EXPECT_FALSE(ok); + + name->toNumeric(ok); + EXPECT_FALSE(ok); + + auto defaultName = name->toString(ok); + ASSERT_TRUE(ok); + EXPECT_TRUE(defaultName == "Text Editor"); + + auto localeString = name->toLocaleString(QLocale{"zh_CN"}, ok); + ASSERT_TRUE(ok); + + EXPECT_TRUE(localeString == "文本编辑器"); +} diff --git a/tests/ut_jobmanager.cpp b/tests/ut_jobmanager.cpp new file mode 100644 index 0000000..ac793ef --- /dev/null +++ b/tests/ut_jobmanager.cpp @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "jobmanager1service.h" +#include "jobservice.h" +#include + +class TestJobManager : public testing::Test +{ +public: + JobManager1Service& service() { return m_jobManager; } +private: + JobManager1Service m_jobManager; +}; + +TEST_F(TestJobManager, addJob) +{ + QDBusObjectPath sourcePath{"/org/deepin/Test1"}; + QVariantList args{{"Application"}, {"Application"}, {"Application"}, {"Application"}}; + auto &manager = service(); + QDBusObjectPath jobPath; + QObject::connect(&manager, &JobManager1Service::JobNew, [&](const QDBusObjectPath &job, const QDBusObjectPath &source) { + jobPath = job; + EXPECT_TRUE(source == sourcePath); + }); + QObject::connect(&manager, + &JobManager1Service::JobRemoved, + [&](const QDBusObjectPath &job, const QString &status, const QVariantList &result) { + EXPECT_TRUE(jobPath == job); + EXPECT_TRUE(status == "finished"); + EXPECT_TRUE(result.count() == 4); + qDebug() << "job was really removed"; + }); + + manager.addJob(sourcePath, [](auto value) -> QVariant { + EXPECT_TRUE(value.toString() == "Application"); + return QVariant::fromValue(true); + }, args); + QThread::sleep(1); // force wait +} diff --git a/tests/utils.cpp b/tests/utils.cpp new file mode 100644 index 0000000..3b7a5ec --- /dev/null +++ b/tests/utils.cpp @@ -0,0 +1,6 @@ +#include "global.h" + +bool registerObjectToDbus(QObject *, const QString &, const QString &) +{ + return true; +}