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
121 changes: 115 additions & 6 deletions tests/src/ut_debugtimemanager.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,125 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2022-2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "DebugTimeManager.h"

Check warning on line 5 in tests/src/ut_debugtimemanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "DebugTimeManager.h" not found.
#include <stub.h>

Check warning on line 6 in tests/src/ut_debugtimemanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <stub.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <gtest/gtest.h>

Check warning on line 7 in tests/src/ut_debugtimemanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <gtest/gtest.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <time.h>

Check warning on line 8 in tests/src/ut_debugtimemanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

// --- clock_gettime stub helpers ---
// Controls whether the stubbed clock_gettime reports failure.
static int g_ut_clock_fail = 0;
static int ut_stub_clock_gettime(clockid_t, struct timespec *tp)
{
if (g_ut_clock_fail) {
return -1;
}
tp->tv_sec = 100;
tp->tv_nsec = 200;
return 0;
}

// getInstance: returns the same non-null singleton each call.
TEST(UT_DebugTimeManager, getInstance_returnsSameSingleton)
{
DebugTimeManager *first = DebugTimeManager::getInstance();
DebugTimeManager *second = DebugTimeManager::getInstance();
ASSERT_NE(first, nullptr);
EXPECT_EQ(first, second);
}

// Protected constructor (accessible via -fno-access-control): constructs without crash.
TEST(UT_DebugTimeManager, constructor_constructsInstance)
{
DebugTimeManager *manager = new DebugTimeManager();
ASSERT_NE(manager, nullptr);
manager->clear();
delete manager;
}

// clear: removes entries previously inserted into the linux point map.
TEST(UT_DebugTimeManager, clear_emptiesPointMaps)
{
DebugTimeManager *manager = new DebugTimeManager();
manager->beginPointLinux("clearPoint", "clearStatus");
ASSERT_TRUE(manager->m_MapLinuxPoint.contains("clearPoint"));
manager->clear();
EXPECT_TRUE(manager->m_MapLinuxPoint.isEmpty());
EXPECT_TRUE(manager->m_MapPoint.isEmpty());
delete manager;
}

// beginPointLinux: success path inserts the point with the given status.
TEST(UT_DebugTimeManager, beginPointLinux_insertsPointOnSuccess)
{
DebugTimeManager *manager = new DebugTimeManager();
manager->beginPointLinux("beginOk", "okStatus");
EXPECT_TRUE(manager->m_MapLinuxPoint.contains("beginOk"));
EXPECT_EQ(manager->m_MapLinuxPoint.value("beginOk").desc, QString("okStatus"));
delete manager;
}

// beginPointLinux: clock_gettime failure path skips insertion.
TEST(UT_DebugTimeManager, beginPointLinux_skipsInsertionOnClockFail)
{
Stub stub;
g_ut_clock_fail = 1;
stub.set(clock_gettime, ut_stub_clock_gettime);
DebugTimeManager *manager = new DebugTimeManager();
manager->beginPointLinux("beginFail", "failStatus");
EXPECT_FALSE(manager->m_MapLinuxPoint.contains("beginFail"));
delete manager;
g_ut_clock_fail = 0;
}

// endPointLinux: normal path removes the previously begun point.
TEST(UT_DebugTimeManager, endPointLinux_removesPointAfterBegin)
{
DebugTimeManager *manager = new DebugTimeManager();
manager->beginPointLinux("endOk", "endStatus");
ASSERT_TRUE(manager->m_MapLinuxPoint.contains("endOk"));
manager->endPointLinux("endOk", "finished");
EXPECT_FALSE(manager->m_MapLinuxPoint.contains("endOk"));
delete manager;
}

// endPointLinux: unknown point is a no-op (no crash, nothing inserted).
TEST(UT_DebugTimeManager, endPointLinux_unknownPointIsNoop)
{
DebugTimeManager *manager = new DebugTimeManager();
manager->endPointLinux("notBegun", "status");
EXPECT_FALSE(manager->m_MapLinuxPoint.contains("notBegun"));
delete manager;
}

// endPointLinux: clock_gettime failure keeps the point (not removed).
TEST(UT_DebugTimeManager, endPointLinux_keepsPointOnClockFail)
{
DebugTimeManager *manager = new DebugTimeManager();
manager->beginPointLinux("endFail", "endFailStatus");
ASSERT_TRUE(manager->m_MapLinuxPoint.contains("endFail"));
Stub stub;
g_ut_clock_fail = 1;
stub.set(clock_gettime, ut_stub_clock_gettime);
manager->endPointLinux("endFail", "finished");
EXPECT_TRUE(manager->m_MapLinuxPoint.contains("endFail"));
g_ut_clock_fail = 0;
delete manager;
}

TEST(UT_DebugTimeManager_clear, UT_DebugTimeManager_clear_001)
// diff: computes the difference between two timespecs.
TEST(UT_DebugTimeManager, diff_computesDifference)
{
DebugTimeManager *Dtime = new DebugTimeManager();
ASSERT_TRUE(Dtime);
Dtime->clear();
delete Dtime;
DebugTimeManager *manager = new DebugTimeManager();
timespec start;
start.tv_sec = 10;
start.tv_nsec = 100;
timespec end;
end.tv_sec = 35;
end.tv_nsec = 500;
timespec result = manager->diff(start, end);
EXPECT_EQ(result.tv_sec, 25);
EXPECT_EQ(result.tv_nsec, 400);
delete manager;
}
210 changes: 210 additions & 0 deletions tests/src/ut_logcollectormain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@
#include "logapplicationhelper.h"
#include <stub.h>

#include <DTitlebar>

Check warning on line 14 in tests/src/ut_logcollectormain.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 15 in tests/src/ut_logcollectormain.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 16 in tests/src/ut_logcollectormain.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 17 in tests/src/ut_logcollectormain.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 18 in tests/src/ut_logcollectormain.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

#include <QKeyEvent>

Check warning on line 20 in tests/src/ut_logcollectormain.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QKeyEvent> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDebug>
#include <QList>
#include <QDir>
#include "dbusmanager.h"
#include "dbusproxy/dldbushandler.h"
#include "logallexportthread.h"

#include <gtest/gtest.h>

Expand Down Expand Up @@ -412,3 +417,208 @@
}



// ===== Tests added to cover lambda closures (target: 100% function coverage) =====

#include <QMetaObject>
#include <QTimer>
#include <QFutureWatcher>
#include <QtConcurrent>
#include <QEventLoop>
#include <QTest>
#include <DIconButton>

// Stub: LogAllExportThread::run — emit signals to trigger the lambdas connected in exportAllLogs
void LogAllExportThread_run_stub(LogAllExportThread *self)
{
self->updateTolProcess(100);
self->updatecurrentProcess(50);
self->exportFinsh(true);
}

// Stub: DLDBusHandler::whiteListOutPaths — return non-empty list so export path check passes
QStringList DLDBusHandler_whiteListOutPaths_stub()
{
return QStringList() << "." << "/" << QDir::homePath();
}

// Stub: DBusManager::isSEOpen
bool DBusManager_isSEOpen_stub()
{
return false;
}

// Stub: DBusManager::isAuditAdmin
bool DBusManager_isAuditAdmin_stub()
{
return false;
}

// Stub: DBusManager::isScreenLocked — return false so refresh lambda else-branch fires
bool DBusManager_isScreenLocked_false()
{
return false;
}

// Stub: DDialog::exec that processes events so queued lambdas can fire
int LogCollectorMain_exec_processEvents(DDialog *self)
{
Q_UNUSED(self)
// Process events for a short time to let thread signals fire
QTest::qWait(500);
return 1;
}

// ===== initShortCut lambda coverage =====
TEST(LogCollectorMain_initShortCut_UT, LogCollectorMain_initShortCut_UT_003)
{
// Set DStyle so DApplication::style() returns a valid DStyle* — prevents SEGV
// in LogPeriodButton::paintEvent when showMaximized()/showNormal() triggers repaints
qApp->setStyle(new DStyle);
Stub stub;
stub.set(ADDR(DebugTimeManager, beginPointLinux), Log_beginPointLinux);
stub.set(ADDR(LogFileParser, parseByJournal), LogFileParser_parseByJournal);
stub.set(ADDR(LogFileParser, parseByJournalBoot), LogFileParser_parseByJournalBoot);
stub.set(ADDR(LogFileParser, parseByDpkg), LogFileParser_parseByDpkg);
stub.set(ADDR(LogFileParser, parseByXlog), LogFileParser_parseByXlog);
stub.set(ADDR(LogFileParser, parseByBoot), LogFileParser_parseByBoot);
stub.set(ADDR(LogFileParser, parseByKern), LogFileParser_parseByKern);
stub.set(ADDR(LogFileParser, parseByApp), LogFileParser_parseByApp);
stub.set(ADDR(LogFileParser, parseByNormal), LogFileParser_parseByNormal);
stub.set(ADDR(LogFileParser, parseByKwin), LogFileParser_parseByKwin);
stub.set(ADDR(LogApplicationHelper, getCustomLogList), LogApplicationHelper_getCustomLogList);
LogCollectorMain *p = new LogCollectorMain(nullptr);
ASSERT_TRUE(p);

// Emit the activated signal on each shortcut to invoke the lambdas
if (p->m_scWndReize) {
QMetaObject::invokeMethod(p->m_scWndReize, "activated");
}
if (p->m_scFindFont) {
QMetaObject::invokeMethod(p->m_scFindFont, "activated");
}
if (p->m_scExport) {
QMetaObject::invokeMethod(p->m_scExport, "activated");
}
// Process events so signal lambdas execute
QTest::qWait(100);

p->deleteLater();
}

// ===== initTitlebarExtensions lambda coverage =====
TEST(LogCollectorMain_initTitlebarExtensions_UT, LogCollectorMain_initTitlebarExtensions_UT_002)
{
Stub stub;
stub.set(ADDR(DebugTimeManager, beginPointLinux), Log_beginPointLinux);
stub.set(ADDR(LogFileParser, parseByJournal), LogFileParser_parseByJournal);
stub.set(ADDR(LogFileParser, parseByJournalBoot), LogFileParser_parseByJournalBoot);
stub.set(ADDR(LogFileParser, parseByDpkg), LogFileParser_parseByDpkg);
stub.set(ADDR(LogFileParser, parseByXlog), LogFileParser_parseByXlog);
stub.set(ADDR(LogFileParser, parseByBoot), LogFileParser_parseByBoot);
stub.set(ADDR(LogFileParser, parseByKern), LogFileParser_parseByKern);
stub.set(ADDR(LogFileParser, parseByApp), LogFileParser_parseByApp);
stub.set(ADDR(LogFileParser, parseByNormal), LogFileParser_parseByNormal);
stub.set(ADDR(LogFileParser, parseByKwin), LogFileParser_parseByKwin);
stub.set(ADDR(LogApplicationHelper, getCustomLogList), LogApplicationHelper_getCustomLogList);
typedef bool (*fptr)(LogApplication *);
fptr test = (fptr)(&LogApplication::notify);
stub.set(test, LogCollectorMain_notify);
LogCollectorMain *p = new LogCollectorMain(nullptr);
ASSERT_TRUE(p);

// Click the refresh button to trigger the clicked lambda
if (p->m_refreshBtn) {
p->m_refreshBtn->click();
}
QTest::qWait(100);

p->deleteLater();
}

// ===== switchRefreshActionTriggered lambda coverage =====
TEST(LogCollectorMain_switchRefreshActionTriggered_UT, LogCollectorMain_switchRefreshActionTriggered_UT_002)
{
Stub stub;
stub.set(ADDR(DebugTimeManager, beginPointLinux), Log_beginPointLinux);
stub.set(ADDR(LogFileParser, parseByJournal), LogFileParser_parseByJournal);
stub.set(ADDR(LogFileParser, parseByJournalBoot), LogFileParser_parseByJournalBoot);
stub.set(ADDR(LogFileParser, parseByDpkg), LogFileParser_parseByDpkg);
stub.set(ADDR(LogFileParser, parseByXlog), LogFileParser_parseByXlog);
stub.set(ADDR(LogFileParser, parseByBoot), LogFileParser_parseByBoot);
stub.set(ADDR(LogFileParser, parseByKern), LogFileParser_parseByKern);
stub.set(ADDR(LogFileParser, parseByApp), LogFileParser_parseByApp);
stub.set(ADDR(LogFileParser, parseByNormal), LogFileParser_parseByNormal);
stub.set(ADDR(LogFileParser, parseByKwin), LogFileParser_parseByKwin);
stub.set(ADDR(LogApplicationHelper, getCustomLogList), LogApplicationHelper_getCustomLogList);
typedef bool (*fptr)(LogApplication *);
fptr test = (fptr)(&LogApplication::notify);
stub.set(test, LogCollectorMain_notify);
// Stub DBusManager::isScreenLocked so QtConcurrent::run completes quickly
stub.set(ADDR(DBusManager, isScreenLocked), DBusManager_isScreenLocked_false);
LogCollectorMain *p = new LogCollectorMain(nullptr);
ASSERT_TRUE(p);

// Use the actual refresh action at index 0 ("10 sec") so indexOf returns 0
// and timeInterval = 10*1000 > 0, which creates the timer.
if (!p->m_refreshActions.isEmpty()) {
p->switchRefreshActionTriggered(p->m_refreshActions[0]);
}

// Now trigger the timer timeout to invoke the outer lambda
if (p->m_refreshTimer) {
p->m_refreshTimer->stop();
// Emit timeout signal to invoke the lambda connected in switchRefreshActionTriggered
QMetaObject::invokeMethod(p->m_refreshTimer, "timeout");
// Wait for QtConcurrent::run(DBusManager::isScreenLocked) to complete
// and the QFutureWatcher::finished lambda to fire
QTest::qWait(2000);
}
p->deleteLater();
}

// ===== exportAllLogs lambda coverage =====
TEST(LogCollectorMain_exportAllLogs_UT, LogCollectorMain_exportAllLogs_UT_003)
{
Stub stub;
stub.set(ADDR(DebugTimeManager, beginPointLinux), Log_beginPointLinux);
stub.set(ADDR(LogFileParser, parseByJournal), LogFileParser_parseByJournal);
stub.set(ADDR(LogFileParser, parseByJournalBoot), LogFileParser_parseByJournalBoot);
stub.set(ADDR(LogFileParser, parseByDpkg), LogFileParser_parseByDpkg);
stub.set(ADDR(LogFileParser, parseByXlog), LogFileParser_parseByXlog);
stub.set(ADDR(LogFileParser, parseByBoot), LogFileParser_parseByBoot);
stub.set(ADDR(LogFileParser, parseByKern), LogFileParser_parseByKern);
stub.set(ADDR(LogFileParser, parseByApp), LogFileParser_parseByApp);
stub.set(ADDR(LogFileParser, parseByNormal), LogFileParser_parseByNormal);
stub.set(ADDR(LogFileParser, parseByKwin), LogFileParser_parseByKwin);
stub.set(ADDR(LogApplicationHelper, getCustomLogList), LogApplicationHelper_getCustomLogList);
typedef bool (*fptr)(LogApplication *);
fptr test = (fptr)(&LogApplication::notify);
stub.set(test, LogCollectorMain_notify);
LogCollectorMain *p = new LogCollectorMain(nullptr);
ASSERT_TRUE(p);

// Authorization: use true so auth passes (static bool already set true by UT_002,
// but set it anyway for independence)
stub.set(ADDR(Utils, checkAuthorization), LogCollectorMain_checkAuthorization_true);
// File dialog returns a path
stub.set(ADDR(QFileDialog, getSaveFileName), LogCollectorMain_QString);
// Whitelist returns non-empty so path check passes
stub.set(ADDR(DLDBusHandler, whiteListOutPaths), DLDBusHandler_whiteListOutPaths_stub);
// DBus checks stubbed to avoid hangs
stub.set(ADDR(DBusManager, isSEOpen), DBusManager_isSEOpen_stub);
stub.set(ADDR(DBusManager, isAuditAdmin), DBusManager_isAuditAdmin_stub);
// DDialog::exec processes events so thread signals fire the lambdas
typedef int (*fptr2)(DDialog *);
fptr2 test1 = (fptr2)(&DDialog::exec);
stub.set(test1, LogCollectorMain_exec_processEvents);
// Stub LogAllExportThread::run to emit the 3 signals so the connected lambdas fire
typedef void (*fptr_run)(LogAllExportThread *);
fptr_run run_ptr = (fptr_run)(&LogAllExportThread::run);
stub.set(run_ptr, LogAllExportThread_run_stub);

p->exportAllLogs();
QTest::qWait(500);

p->deleteLater();
}
Loading
Loading