feat: add test for desktopentry and jobmanager
Log:
This commit is contained in:
parent
d288752fb3
commit
5fed3ed9f0
@ -32,3 +32,8 @@ License: CC0-1.0
|
|||||||
Files: rpm/* debian/* archlinux/*
|
Files: rpm/* debian/* archlinux/*
|
||||||
Copyright: None
|
Copyright: None
|
||||||
License: CC0-1.0
|
License: CC0-1.0
|
||||||
|
|
||||||
|
# test
|
||||||
|
Files: tests/data/*
|
||||||
|
Copyright: None
|
||||||
|
License: CC0-1.0
|
||||||
|
@ -16,7 +16,40 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
|
|||||||
find_package(Qt6 REQUIRED COMPONENTS Core DBus Concurrent)
|
find_package(Qt6 REQUIRED COMPONENTS Core DBus Concurrent)
|
||||||
find_package(Threads REQUIRED)
|
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(src)
|
||||||
# add_subdirectory(docs)
|
# add_subdirectory(docs)
|
||||||
# add_subdirectory(tests)
|
|
||||||
# add_subdirectory(plugin)
|
# add_subdirectory(plugin)
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
enable_testing()
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif()
|
||||||
|
@ -1,31 +1,26 @@
|
|||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
set(BIN_NAME dde-application-manager)
|
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 "")
|
list(REMOVE_ITEM SRCS "${PROJECT_SOURCE_DIR}/src/utils.cpp")
|
||||||
file(GLOB_RECURSE SRCS ${CMAKE_CURRENT_LIST_DIR}/*.cpp ${CMAKE_CURRENT_LIST_DIR}/*.h)
|
|
||||||
|
|
||||||
qt_add_dbus_adaptor(DBUSADAPTORS ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ApplicationManager1.xml applicationmanager1service.h ApplicationManager1Service)
|
add_library(${LIB_NAME} ${SRCS})
|
||||||
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_executable(${BIN_NAME} ${DBUSADAPTORS} ${SRCS})
|
target_include_directories(${LIB_NAME} PRIVATE
|
||||||
|
${PROJECT_BINARY_DIR}
|
||||||
target_include_directories(${BIN_NAME} PRIVATE
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/include
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/dbus
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/src
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${BIN_NAME} PRIVATE
|
target_link_libraries(${LIB_NAME} PUBLIC
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
|
||||||
Qt${QT_VERSION_MAJOR}::DBus
|
|
||||||
Qt${QT_VERSION_MAJOR}::Concurrent
|
|
||||||
Threads::Threads
|
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})
|
install(TARGETS ${BIN_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
#include "applicationmanager1service.h"
|
#include "applicationmanager1service.h"
|
||||||
#include "applicationmanager1adaptor.h"
|
|
||||||
#include "applicationadaptor.h"
|
#include "applicationadaptor.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
@ -46,7 +45,7 @@ QDBusObjectPath ApplicationManager1Service::Launch(const QString &id,
|
|||||||
objectPath.prepend(DDEApplicationManager1ApplicationObjectPath);
|
objectPath.prepend(DDEApplicationManager1ApplicationObjectPath);
|
||||||
QSharedPointer<ApplicationService> app{new ApplicationService{id}};
|
QSharedPointer<ApplicationService> app{new ApplicationService{id}};
|
||||||
auto *ptr = app.data();
|
auto *ptr = app.data();
|
||||||
if (registerObjectToDbus<decltype(ptr), ApplicationAdaptor>(ptr, objectPath, getDBusInterface<ApplicationAdaptor>())) {
|
if (registerObjectToDbus(new ApplicationAdaptor(ptr), objectPath, getDBusInterface<ApplicationAdaptor>())) {
|
||||||
QDBusObjectPath path{objectPath};
|
QDBusObjectPath path{objectPath};
|
||||||
m_applicationList.insert(path, app);
|
m_applicationList.insert(path, app);
|
||||||
return path;
|
return path;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
#include "applicationservice.h"
|
#include "applicationservice.h"
|
||||||
|
#include "applicationadaptor.h"
|
||||||
#include "instanceadaptor.h"
|
#include "instanceadaptor.h"
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
@ -27,7 +28,7 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL
|
|||||||
QString objectPath{m_applicationPath.path() + "/" + QUuid::createUuid().toString()};
|
QString objectPath{m_applicationPath.path() + "/" + QUuid::createUuid().toString()};
|
||||||
QSharedPointer<InstanceService> ins{new InstanceService{objectPath, ""}};
|
QSharedPointer<InstanceService> ins{new InstanceService{objectPath, ""}};
|
||||||
auto *ptr = ins.data();
|
auto *ptr = ins.data();
|
||||||
if (registerObjectToDbus<decltype(ptr), InstanceAdaptor>(ptr, objectPath, getDBusInterface<InstanceAdaptor>())) {
|
if (registerObjectToDbus(new InstanceAdaptor(ptr), objectPath, getDBusInterface<InstanceAdaptor>())) {
|
||||||
m_Instances.insert(QDBusObjectPath{objectPath}, ins);
|
m_Instances.insert(QDBusObjectPath{objectPath}, ins);
|
||||||
return QDBusObjectPath{objectPath};
|
return QDBusObjectPath{objectPath};
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,9 @@ public:
|
|||||||
{
|
{
|
||||||
static_assert(std::is_invocable_v<F, QVariant>, "param type must be QVariant.");
|
static_assert(std::is_invocable_v<F, QVariant>, "param type must be QVariant.");
|
||||||
|
|
||||||
QString objectPath{DDEApplicationManager1JobObjectPath + QUuid::createUuid().toString()};
|
QString objectPath{DDEApplicationManager1JobObjectPath + QUuid::createUuid().toString(QUuid::Id128)};
|
||||||
QFuture<QVariantList> future = QtConcurrent::mappedReduced(
|
auto future = QtConcurrent::mappedReduced(
|
||||||
args.begin(), args.end(), func, &QVariantList::insert, QVariantList{}, QtConcurrent::ReduceOption::OrderedReduce);
|
args.begin(), args.end(), func,qOverload<QVariantList::parameter_type>(&QVariantList::append), QVariantList{}, QtConcurrent::ReduceOption::OrderedReduce);
|
||||||
QSharedPointer<JobService> job{new JobService{future}};
|
QSharedPointer<JobService> job{new JobService{future}};
|
||||||
auto path = QDBusObjectPath{objectPath};
|
auto path = QDBusObjectPath{objectPath};
|
||||||
{
|
{
|
||||||
@ -43,8 +43,8 @@ public:
|
|||||||
m_jobs.insert(path, job); // Insertion is always successful
|
m_jobs.insert(path, job); // Insertion is always successful
|
||||||
}
|
}
|
||||||
emit JobNew(path, source);
|
emit JobNew(path, source);
|
||||||
registerObjectToDbus<decltype(job.data()), JobAdaptor>(job.data(), objectPath, getDBusInterface<JobAdaptor>());
|
registerObjectToDbus(new JobAdaptor(job.data()), objectPath, getDBusInterface<JobAdaptor>());
|
||||||
auto emitRemove = [this, job, path, future] {
|
auto emitRemove = [this, job, path, future] (QVariantList value) {
|
||||||
decltype(m_jobs)::size_type removeCount{0};
|
decltype(m_jobs)::size_type removeCount{0};
|
||||||
{
|
{
|
||||||
QMutexLocker locker{&m_mutex};
|
QMutexLocker locker{&m_mutex};
|
||||||
@ -54,18 +54,19 @@ public:
|
|||||||
// and we shouldn't emit jobRemoved signal because this signal may already has been emit
|
// 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();
|
qCritical() << "Job already has been removed: " << path.path();
|
||||||
return;
|
return value;
|
||||||
}
|
}
|
||||||
QString result{job->status()};
|
QString result{job->status()};
|
||||||
for (const auto &val : future.result()) {
|
for (const auto &val : future.result()) {
|
||||||
if (val.canConvert<QDBusError>()) {
|
if (val.template canConvert<QDBusError>()) {
|
||||||
result = "failed";
|
result = "failed";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
emit this->JobRemoved(path, result, future.result());
|
emit this->JobRemoved(path, result, future.result());
|
||||||
|
return value;
|
||||||
};
|
};
|
||||||
future.then(QtFuture::Launch::Sync, emitRemove);
|
future.then(emitRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
18
src/demo.cpp
18
src/demo.cpp
@ -1,18 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "demo.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
void greet()
|
|
||||||
{
|
|
||||||
std::cout << QString{"Hello"}.toStdString() <<std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
greet();
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -110,18 +110,16 @@ std::optional<DesktopFile> DesktopFile::searchDesktopFile(const QString &desktop
|
|||||||
auto components = path.split(QDir::separator()).toList();
|
auto components = path.split(QDir::separator()).toList();
|
||||||
auto it = std::find(components.cbegin(), components.cend(), "applications");
|
auto it = std::find(components.cbegin(), components.cend(), "applications");
|
||||||
if (it == components.cend()) {
|
if (it == components.cend()) {
|
||||||
qWarning() << "fatal error: file location invalid";
|
qWarning() << "custom location detected, Id wouldn't be generated.";
|
||||||
err = ParseError::InvalidLocation;
|
} else {
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
QString FileId;
|
QString FileId;
|
||||||
++it;
|
++it;
|
||||||
while (it != components.cend())
|
while (it != components.cend())
|
||||||
FileId += (*(it++) + "-");
|
FileId += (*(it++) + "-");
|
||||||
id = FileId.chopped(1);
|
id = FileId.chopped(1);
|
||||||
|
}
|
||||||
err = ParseError::NoError;
|
err = ParseError::NoError;
|
||||||
return DesktopFile{path,id};
|
return DesktopFile{std::move(path),std::move(id)};
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseError DesktopEntry::parse(QTextStream& stream) noexcept
|
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
|
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;
|
ok = false;
|
||||||
|
const auto& str = (*this)[defaultKeyStr];
|
||||||
|
if (str == "true") {
|
||||||
|
ok = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (str == "false") {
|
||||||
|
ok = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,3 +263,41 @@ QDebug operator<<(QDebug debug, const DesktopEntry::Value &v)
|
|||||||
debug << static_cast<const QMap<QString,QString>&>(v);
|
debug << static_cast<const QMap<QString,QString>&>(v);
|
||||||
return debug;
|
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;
|
||||||
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
|
|
||||||
void greet();
|
|
@ -14,7 +14,6 @@ constexpr static auto defaultKeyStr = "default";
|
|||||||
enum class ParseError {
|
enum class ParseError {
|
||||||
NoError,
|
NoError,
|
||||||
NotFound,
|
NotFound,
|
||||||
FilePathEmpty,
|
|
||||||
MismatchedFile,
|
MismatchedFile,
|
||||||
InvalidLocation,
|
InvalidLocation,
|
||||||
OpenFailed,
|
OpenFailed,
|
||||||
@ -37,13 +36,13 @@ public:
|
|||||||
friend QDebug operator<<(QDebug debug, const DesktopEntry::Value &v);
|
friend QDebug operator<<(QDebug debug, const DesktopEntry::Value &v);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString unescape(const QString& str) const noexcept;
|
[[nodiscard]] QString unescape(const QString &str) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
DesktopEntry() = default;
|
DesktopEntry() = default;
|
||||||
~DesktopEntry() = default;
|
~DesktopEntry() = default;
|
||||||
ParseError parse(QTextStream& stream) noexcept;
|
[[nodiscard]] ParseError parse(QTextStream& stream) noexcept;
|
||||||
QMap<QString, Value> group(const QString &key) const noexcept;
|
[[nodiscard]] QMap<QString, Value> group(const QString &key) const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMap<QString, QMap<QString, Value>> m_entryMap;
|
QMap<QString, QMap<QString, Value>> m_entryMap;
|
||||||
@ -54,13 +53,23 @@ private:
|
|||||||
|
|
||||||
struct DesktopFile
|
struct DesktopFile
|
||||||
{
|
{
|
||||||
const QString filePath;
|
DesktopFile(const DesktopFile &) = default;
|
||||||
const QString desktopId;
|
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<DesktopFile> searchDesktopFile(const QString &desktopFilePath, ParseError& err) noexcept;
|
static std::optional<DesktopFile> searchDesktopFile(const QString &desktopFilePath, ParseError& err) noexcept;
|
||||||
|
|
||||||
private:
|
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 DesktopEntry::Value& v);
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, const ParseError &v);
|
||||||
|
@ -52,21 +52,7 @@ private:
|
|||||||
QString m_busAddress;
|
QString m_busAddress;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename U>
|
bool registerObjectToDbus(QObject* o, const QString &path, const QString &interface);
|
||||||
bool registerObjectToDbus(T parent, const QString &path, const QString &interface)
|
|
||||||
{
|
|
||||||
using service_type = std::remove_const_t<T>;
|
|
||||||
static_assert(std::is_pointer_v<service_type>, "param type must be a pointer");
|
|
||||||
static_assert(std::is_base_of_v<QObject, std::remove_pointer_t<T>> and
|
|
||||||
std::is_base_of_v<QObject, U>,
|
|
||||||
"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;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
QString getDBusInterface()
|
QString getDBusInterface()
|
||||||
|
4
src/main.cpp
Normal file
4
src/main.cpp
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
11
src/utils.cpp
Normal file
11
src/utils.cpp
Normal file
@ -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;
|
||||||
|
}
|
39
tests/CMakeLists.txt
Normal file
39
tests/CMakeLists.txt
Normal file
@ -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}
|
||||||
|
)
|
110
tests/data/desktopExample.desktop
Normal file
110
tests/data/desktopExample.desktop
Normal file
@ -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 文字編輯器
|
22
tests/main.cpp
Normal file
22
tests/main.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <sanitizer/asan_interface.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
81
tests/ut_desktopentry.cpp
Normal file
81
tests/ut_desktopentry.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "desktopentry.h"
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QLocale>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
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<DesktopFile> file() { return m_file; }
|
||||||
|
private:
|
||||||
|
static inline QSharedPointer<DesktopFile> 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 == "文本编辑器");
|
||||||
|
}
|
41
tests/ut_jobmanager.cpp
Normal file
41
tests/ut_jobmanager.cpp
Normal file
@ -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 <gtest/gtest.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
6
tests/utils.cpp
Normal file
6
tests/utils.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
bool registerObjectToDbus(QObject *, const QString &, const QString &)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user