Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/common/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,9 @@ QStringList Utils::parseNestedQString(QString str)
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
auto spStr = QRegExp(QStringLiteral("\\s+"));
#else
auto spStr = QStringLiteral("\\s+");
// Qt6 下 split 需要传 QRegularExpression;同时显式 SkipEmptyParts,
// 以避免 "bash -c " 末尾空白产生空字符串元素,与 Qt5 行为保持一致。
auto spStr = QRegularExpression(QStringLiteral("\\s+"));
#endif

// 如果只有一个引号
Expand All @@ -617,16 +619,16 @@ QStringList Utils::parseNestedQString(QString str)
}

qCDebug(common) << "Splitting string by whitespace";
paraList.append(str.split(spStr));
paraList.append(str.split(spStr, SKIP_EMPTY_PARTS));
return paraList;
}

qCDebug(common) << "Processing quoted string with left index:" << iLeft << "right index:" << iRight;
paraList.append(str.left(iLeft).split(spStr));
paraList.append(str.left(iLeft).split(spStr, SKIP_EMPTY_PARTS));
paraList.append(str.mid(iLeft + 1, iRight - iLeft - 1));
if (str.size() != iRight + 1) {
qCDebug(common) << "Adding remaining part after quote";
paraList.append(str.right(str.size() - iRight - 1).split(spStr));
paraList.append(str.right(str.size() - iRight - 1).split(spStr, SKIP_EMPTY_PARTS));
}

qCDebug(common) << "Nested string parsing result:" << paraList;
Expand Down
140 changes: 140 additions & 0 deletions tests/src/main/ut_dbusmanager_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
// SPDX-License-Identifier: GPL-3.0-or-later

#include "ut_dbusmanager_test.h"
#include "dbusmanager.h"

Check warning on line 7 in tests/src/main/ut_dbusmanager_test.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "dbusmanager.h" not found.
#include "settings.h"

Check warning on line 8 in tests/src/main/ut_dbusmanager_test.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "settings.h" not found.
#include "ut_stub_defines.h"

Check warning on line 9 in tests/src/main/ut_dbusmanager_test.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "ut_stub_defines.h" not found.

#include <QSignalSpy>

Check warning on line 11 in tests/src/main/ut_dbusmanager_test.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QSignalSpy> not found. Please note: Cppcheck does not need standard library headers to get proper results.

UT_Dbusmanager_Test::UT_Dbusmanager_Test()
{
m_pDbusManager = new DBusManager();
Expand Down Expand Up @@ -85,5 +88,142 @@
EXPECT_TRUE(UT_STUB_QDBUS_CONNECT_RESULT);
}

// 测试 entry 函数,验证信号 entryArgs 会被发射
TEST_F(UT_Dbusmanager_Test, entry)
{
QStringList args = {"deepin-terminal", "-e", "ls"};
QSignalSpy spy(m_pDbusManager, SIGNAL(entryArgs(QStringList)));
m_pDbusManager->entry(args);
EXPECT_EQ(spy.count(), 1);
}

// 测试 callKDECurrentDesktop 函数(DBus call 通过 stub 拦截,返回 InvalidMessage,函数返回 -1)
TEST_F(UT_Dbusmanager_Test, callKDECurrentDesktop)
{
UT_STUB_QDBUS_CALL_CREATE
int result = m_pDbusManager->callKDECurrentDesktop();
// stub 返回空 QDBusMessage,type() != ReplyMessage,应返回 -1
EXPECT_EQ(result, -1);
EXPECT_TRUE(UT_STUB_QDBUS_CALL_RESULT);
}

// 字体大小 getter/setter
TEST_F(UT_Dbusmanager_Test, consoleFontSize)
{
const int expectSize = 18;
Settings::instance()->setFontSize(expectSize);
EXPECT_EQ(m_pDbusManager->consoleFontSize(), expectSize);
}

TEST_F(UT_Dbusmanager_Test, setConsoleFontSize)
{
const int newSize = 22;
Comment on lines +111 to +120

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider isolating and restoring Settings singleton state to avoid inter-test coupling.

These DBusManager tests mutate Settings::instance() (font size, opacity, cursor shape/blink, color scheme, etc.) and assume its state. Without resetting these fields, tests can become order-dependent and leak state to other suites.

Please either save and restore the affected Settings values per test (or in SetUp/TearDown / an RAII helper) so all modified fields are consistently reset after each test.

Suggested implementation:

class SettingsGuard
{
public:
    SettingsGuard()
        : m_originalFontSize(Settings::instance()->fontSize())
    {
    }

    ~SettingsGuard()
    {
        Settings::instance()->setFontSize(m_originalFontSize);
    }

private:
    int m_originalFontSize;
};

TEST_F(UT_Dbusmanager_Test, callKDECurrentDesktop)
TEST_F(UT_Dbusmanager_Test, consoleFontSize)
{
    SettingsGuard settingsGuard;

    const int expectSize = 18;
    Settings::instance()->setFontSize(expectSize);
    EXPECT_EQ(m_pDbusManager->consoleFontSize(), expectSize);
}
TEST_F(UT_Dbusmanager_Test, setConsoleFontSize)
{
    SettingsGuard settingsGuard;

    const int newSize = 22;
    m_pDbusManager->setConsoleFontSize(newSize);
}

The SettingsGuard currently only preserves and restores fontSize. To fully address inter-test coupling for other Settings fields (opacity, cursor shape/blink, color scheme, etc.), extend SettingsGuard to capture and reset all fields that the DBusManager tests touch, using the corresponding getters/setters (e.g. opacity(), setOpacity(), etc.), and instantiate SettingsGuard in each test that mutates those fields.
If your test fixture (UT_Dbusmanager_Test) already has SetUp/TearDown, you may alternatively move SettingsGuard into a member field and construct it in SetUp so every test in this suite benefits from automatic state restoration.

m_pDbusManager->setConsoleFontSize(newSize);
EXPECT_EQ(Settings::instance()->fontSize(), newSize);
}

// 字体 family getter/setter
TEST_F(UT_Dbusmanager_Test, consoleFontFamily)
{
// 验证 getter 可正常返回(setFontName 依赖 DBus 字体列表,测试环境下走默认值)
const QString family = m_pDbusManager->consoleFontFamily();
EXPECT_FALSE(family.isNull());
}

TEST_F(UT_Dbusmanager_Test, setConsoleFontFamily)
{
// setFontName 会查询 DBus 字体列表,测试环境下大概率匹配不上,仅验证不崩溃
m_pDbusManager->setConsoleFontFamily(QStringLiteral("Noto Sans Mono"));
SUCCEED();
}

// 透明度 getter/setter(Settings 内部把 int 百分比换算为 0~1 的 qreal)
TEST_F(UT_Dbusmanager_Test, consoleOpacity)
{
const int expectPercent = 85;
Settings::instance()->setOpacity(expectPercent);
EXPECT_NEAR(m_pDbusManager->consoleOpacity(), expectPercent / 100.0, 0.001);
}

TEST_F(UT_Dbusmanager_Test, setConsoleOpacity)
{
const int newOpacity = 60;
m_pDbusManager->setConsoleOpacity(newOpacity);
EXPECT_NEAR(Settings::instance()->opacity(), newOpacity / 100.0, 0.001);
}

// 光标形状 getter/setter
TEST_F(UT_Dbusmanager_Test, consoleCursorShape)
{
const int expectShape = 1;
Settings::instance()->setCursorShape(expectShape);
EXPECT_EQ(m_pDbusManager->consoleCursorShape(), expectShape);
}

TEST_F(UT_Dbusmanager_Test, setConsoleCursorShape)
{
const int newShape = 2;
m_pDbusManager->setConsoleCursorShape(newShape);
EXPECT_EQ(Settings::instance()->cursorShape(), newShape);
}

// 光标闪烁 getter/setter
TEST_F(UT_Dbusmanager_Test, consoleCursorBlink)
{
const bool expectBlink = true;
Settings::instance()->setCursorBlink(expectBlink);
EXPECT_EQ(m_pDbusManager->consoleCursorBlink(), expectBlink);
}

TEST_F(UT_Dbusmanager_Test, setConsoleCursorBlink)
{
const bool newBlink = false;
m_pDbusManager->setConsoleCursorBlink(newBlink);
EXPECT_EQ(Settings::instance()->cursorBlink(), newBlink);
}

// 配色方案 getter/setter
TEST_F(UT_Dbusmanager_Test, consoleColorScheme)
{
EXPECT_FALSE(m_pDbusManager->consoleColorScheme().isEmpty());
}

TEST_F(UT_Dbusmanager_Test, setConsoleColorScheme)
{
const QString newScheme = QStringLiteral("Dark");
m_pDbusManager->setConsoleColorScheme(newScheme);
EXPECT_EQ(Settings::instance()->colorScheme(), newScheme);
}

// shell 路径 getter/setter
TEST_F(UT_Dbusmanager_Test, consoleShell)
{
EXPECT_FALSE(m_pDbusManager->consoleShell().isEmpty());
}

TEST_F(UT_Dbusmanager_Test, setConsoleShell)
{
// setConsoleShell 会从 /etc/shells 找匹配,匹配不上时不动设置;这里只验证不崩溃
m_pDbusManager->setConsoleShell(QStringLiteral("/bin/bash"));
SUCCEED();
}

// 测试 callSystemSound(依赖 DBus call,验证函数能正常执行)
TEST_F(UT_Dbusmanager_Test, callSystemSound)
{
UT_STUB_QDBUS_CALL_CREATE
m_pDbusManager->callSystemSound(QStringLiteral("message"));
EXPECT_TRUE(UT_STUB_QDBUS_CALL_RESULT);
}

// 测试 callAppearanceFont 的重载版本(传入空列表)
TEST_F(UT_Dbusmanager_Test, callAppearanceFontFromList)
{
UT_STUB_QDBUS_CALL_CREATE
FontDataList result = m_pDbusManager->callAppearanceFont(QStringList(), QStringLiteral("monospacefont"));
EXPECT_TRUE(result.isEmpty());
EXPECT_TRUE(UT_STUB_QDBUS_CALL_RESULT);
}

#endif

11 changes: 8 additions & 3 deletions tests/src/main/ut_service_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,10 +394,15 @@ TEST_F(UT_Service_Test, hideSettingDialog)
if(nullptr == m_service->m_settingDialog)
m_service->m_settingDialog = new DSettingsDialog();

UT_STUB_QWIDGET_SETVISIBLE_CREATE;
// Qt6 中 QWidget::hide() 通过虚表 jmp 到 setVisible(false),
// stub-ext 改 setVisible 入口字节码对虚表跳转无效,因此直接 stub hide()
Stub stub;
stub.set((void (QWidget::*)())ADDR(QWidget, hide), ut_QWidget_update);
ut_QWidget_update_hasRuned = false;

m_service->hideSettingDialog();
//会调用setvisible函数
EXPECT_TRUE(UT_STUB_QWIDGET_SETVISIBLE_RESULT);
// hideSettingDialog 内部会调用 hide()
EXPECT_TRUE(ut_QWidget_update_hasRuned);
}

#endif
10 changes: 8 additions & 2 deletions tests/src/remotemanage/ut_remotemanagementpanel_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,11 @@ TEST_F(UT_RemoteManagementPanel_Test, refreshSearchState)
panel.refreshPanel();
// 两个数据,搜索框显示
panel.refreshSearchState();
// list中数据的数量
// list中数据的数量:
// fillManagePanel 末尾会追加 "Groups"(GroupLabel) 和 "Servers"(ItemLabel) 两个标题项,
// 它们也计入 m_listWidget->count(),所以总数 = 服务器配置数 + 标题数。
int count = panel.m_listWidget->count();
EXPECT_EQ(count, 2);
EXPECT_EQ(count, 2 /* server items */ + 2 /* GroupLabel + ItemLabel */);
ServerConfigManager::instance()->m_serverConfigs.clear();
}

Expand Down Expand Up @@ -358,6 +360,10 @@ TEST_F(UT_RemoteManagementPanel_Test, lambda)
RemoteManagementPanel remotePanel;
remotePanel.show();
remotePanel.m_isShow = true;
// 清理 ServerConfigManager 单例中 SetUp/preparedData 残留的配置,
// 避免下面 refreshList 信号触发 refreshPanel 后,
// 列表中存在可聚焦的服务器项导致 m_currentIndex 被设置。
ServerConfigManager::instance()->m_serverConfigs.clear();
// 刷新界面
emit ServerConfigManager::instance()->refreshList();

Expand Down
125 changes: 125 additions & 0 deletions tests/src/settings/ut_newdspinbox_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,129 @@ TEST_F(UT_NewDSpinBox_Test, eventFilter_Key_Down)
spinBox->deleteLater();
}

// 设置字体大小范围(5~50),验证边界值不越界
TEST_F(UT_NewDSpinBox_Test, setRange_FontRange)
{
NewDspinBox *spinBox = new NewDspinBox;
spinBox->setRange(5, 50);
spinBox->setValue(50);
EXPECT_EQ(spinBox->value(), 50);
spinBox->setValue(5);
EXPECT_EQ(spinBox->value(), 5);
spinBox->deleteLater();
}

// 设置历史记录范围(1000~10000),setRange 会把 minimum 放宽到 1
TEST_F(UT_NewDSpinBox_Test, setRange_HistoryRange)
{
NewDspinBox *spinBox = new NewDspinBox;
spinBox->setRange(1000, 10000);
// 此时允许临时输入更小的值进行智能补全
spinBox->setValue(1);
EXPECT_EQ(spinBox->value(), 1);
spinBox->setValue(10000);
EXPECT_EQ(spinBox->value(), 10000);
spinBox->deleteLater();
}

// 设置其它范围,验证通用范围分支
TEST_F(UT_NewDSpinBox_Test, setRange_OtherRange)
{
NewDspinBox *spinBox = new NewDspinBox;
spinBox->setRange(100, 500);
spinBox->setValue(100);
EXPECT_EQ(spinBox->value(), 100);
spinBox->deleteLater();
}

// 测试 keyPressEvent 在历史记录范围下按 Enter 触发智能补全(输入 5 -> 5000)
TEST_F(UT_NewDSpinBox_Test, keyPressEvent_EnterSmartComplete)
{
NewDspinBox *spinBox = new NewDspinBox;
spinBox->setRange(1000, 10000);
spinBox->lineEdit()->setText("5");
QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
QApplication::sendEvent(spinBox, &event);
EXPECT_EQ(spinBox->value(), 5000);
spinBox->deleteLater();
}

// 测试 keyPressEvent 在历史记录范围下按非 Enter 键不触发智能补全
TEST_F(UT_NewDSpinBox_Test, keyPressEvent_OtherKey)
{
NewDspinBox *spinBox = new NewDspinBox;
spinBox->setRange(1000, 10000);
spinBox->setValue(2000);
QKeyEvent event(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier);
QApplication::sendEvent(spinBox, &event);
// 普通按键不会触发智能补全逻辑,值保持不变
EXPECT_EQ(spinBox->value(), 2000);
spinBox->deleteLater();
}

// 测试 keyPressEvent 在字体大小范围下按 Enter 不触发智能补全
TEST_F(UT_NewDSpinBox_Test, keyPressEvent_Enter_FontRange)
{
NewDspinBox *spinBox = new NewDspinBox;
spinBox->setRange(5, 50);
spinBox->setValue(20);
QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
QApplication::sendEvent(spinBox, &event);
// 字体范围不会进入智能补全逻辑
EXPECT_EQ(spinBox->value(), 20);
spinBox->deleteLater();
}

// 测试 focusOutEvent 在历史记录范围下触发智能补全
TEST_F(UT_NewDSpinBox_Test, focusOutEvent_HistoryRange)
{
NewDspinBox *spinBox = new NewDspinBox;
spinBox->setRange(1000, 10000);
spinBox->lineEdit()->setText("22");
QFocusEvent event(QEvent::FocusOut);
QApplication::sendEvent(spinBox, &event);
// 22 -> 2200
EXPECT_EQ(spinBox->value(), 2200);
spinBox->deleteLater();
}

// 测试 focusOutEvent 在字体范围下不触发智能补全
TEST_F(UT_NewDSpinBox_Test, focusOutEvent_FontRange)
{
NewDspinBox *spinBox = new NewDspinBox;
spinBox->setRange(5, 50);
spinBox->setValue(20);
QFocusEvent event(QEvent::FocusOut);
QApplication::sendEvent(spinBox, &event);
EXPECT_EQ(spinBox->value(), 20);
spinBox->deleteLater();
}

// 测试 focusOutEvent 在历史记录范围下输入无效文本时使用当前值兜底
TEST_F(UT_NewDSpinBox_Test, focusOutEvent_InvalidText)
{
NewDspinBox *spinBox = new NewDspinBox;
spinBox->setRange(1000, 10000);
spinBox->setValue(3000);
spinBox->lineEdit()->setText("abc");
QFocusEvent event(QEvent::FocusOut);
QApplication::sendEvent(spinBox, &event);
// 无效输入应使用 value() 兜底,smartComplete(3000) 返回 3000
EXPECT_EQ(spinBox->value(), 3000);
spinBox->deleteLater();
}

// 测试 wheelEvent 在无焦点时不响应(直接 return,不调用基类)
TEST_F(UT_NewDSpinBox_Test, wheelEvent_NoFocus)
{
NewDspinBox *spinBox = new NewDspinBox;
spinBox->setValue(20);
// 默认情况下没有焦点,wheelEvent 不应改变值
QWheelEvent event(QPointF(63, 29), QPointF(63, 29), QPoint(0, 120), QPoint(0, 120),
Qt::NoButton, Qt::NoModifier, Qt::ScrollUpdate, false);
QApplication::sendEvent(spinBox, &event);
EXPECT_EQ(spinBox->value(), 20);
spinBox->deleteLater();
}

#endif
17 changes: 15 additions & 2 deletions tests/src/settings/ut_settings_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,24 @@ TEST_F(UT_Settings_Test, SettingsTest)
EXPECT_TRUE(UT_STUB_DSETTINGSOPTION_VALUE_RESULT);
}

// Qt6 中 QObject::tr() 走 QCoreApplication::translate 静态函数,
// 而非 QTranslator::translate 虚函数。直接 stub 静态符号才能拦截。
static bool ut_QCoreApplication_translate_hasRuned = false;
static QString ut_QCoreApplication_translate(const char *, const char *, const char *, int)
{
ut_QCoreApplication_translate_hasRuned = true;
return QString();
}

TEST_F(UT_Settings_Test, GenerateSettingTranslate)
{
UT_STUB_QTRANSLATE_TRANSLATE_CREATE;
using TranslateFunc = QString (*)(const char *, const char *, const char *, int);
Stub stub;
stub.set((TranslateFunc)ADDR(QCoreApplication, translate), ut_QCoreApplication_translate);
ut_QCoreApplication_translate_hasRuned = false;

GenerateSettingTranslate();
EXPECT_TRUE(UT_STUB_QTRANSLATE_TRANSLATE_RESULT);
EXPECT_TRUE(ut_QCoreApplication_translate_hasRuned);
}

TEST_F(UT_Settings_Test, createSpinButtonHandle)
Expand Down
Loading
Loading