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
127 changes: 127 additions & 0 deletions tests/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# tests/common —— src/common 模块单元测试(B2 批次)
# 每个类一个独立测试目标:test_settings / test_config / test_utils / test_urlinfo / test_eventlog

set(QT_VERSION 6)
set(STUB_SHADOW "${CMAKE_SOURCE_DIR}/tests/3rdparty/stub/stub-shadow.cpp")

# QSignalSpy 需要 QtTest;根 tests/CMakeLists.txt 未包含该组件,此处补找
find_package(Qt6 REQUIRED COMPONENTS Test)
set(COMMON_INCLUDE_DIRS
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/common
${CMAKE_SOURCE_DIR}/src/widgets
${CMAKE_SOURCE_DIR}/src/controls
${CMAKE_SOURCE_DIR}/src/basepub
${CMAKE_SOURCE_DIR}/tests/3rdparty/stub
)

# ---------------------------------------------------------------------------
# 测试资源:qss / svg / encodes.ini / settings.json(由项目模板生成,路径回填 qrc)
# ---------------------------------------------------------------------------
set(THEME_DEFAULT_PATH "/usr/share/deepin-editor/themes/deepin.theme")
set(TEST_DATA_DIR ${CMAKE_CURRENT_BINARY_DIR}/test_data)
configure_file(
"${CMAKE_SOURCE_DIR}/src/resources/settings.json.in"
"${TEST_DATA_DIR}/settings.json"
@ONLY
)
configure_file("test_data/test.qss" "${TEST_DATA_DIR}/test.qss" COPYONLY)
configure_file("test_data/test.svg" "${TEST_DATA_DIR}/test.svg" COPYONLY)
configure_file("test_data/encodes.ini" "${TEST_DATA_DIR}/encodes.ini" COPYONLY)
configure_file("ut_resources.qrc.in" "${CMAKE_CURRENT_BINARY_DIR}/ut_resources.qrc" @ONLY)

set(UT_RESOURCES_QRC ${CMAKE_CURRENT_BINARY_DIR}/ut_resources.qrc)

# 源码文件(按类分目标编译,保证 lcov 按目标隔离)
set(SETTINGS_SOURCES
${CMAKE_SOURCE_DIR}/src/common/settings.cpp
${CMAKE_SOURCE_DIR}/src/widgets/pathsettintwgt.cpp
)
set(UTILS_SOURCES
${CMAKE_SOURCE_DIR}/src/common/utils.cpp
${CMAKE_SOURCE_DIR}/src/basepub/load_libs.c
)
set(URLINFO_SOURCES
${CMAKE_SOURCE_DIR}/src/common/utils.cpp
${CMAKE_SOURCE_DIR}/src/basepub/load_libs.c
)
set(CONFIG_SOURCES
${CMAKE_SOURCE_DIR}/src/common/config.cpp
)
set(EVENTLOG_SOURCES
${CMAKE_SOURCE_DIR}/src/common/eventlogutils.cpp
)

# ---------------------------------------------------------------------------
# 公共目标辅助函数
# ---------------------------------------------------------------------------
function(add_ut_target TARGET_NAME)
cmake_parse_arguments(UT "" "" "SOURCES;QT_LIBS;DTK_LIBS;EXTRA_LIBS" ${ARGN})
add_executable(${TARGET_NAME} ${UT_SOURCES} ${STUB_SHADOW})
set_target_properties(${TARGET_NAME} PROPERTIES AUTOMOC ON AUTORCC ON)
target_include_directories(${TARGET_NAME} PRIVATE ${COMMON_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME}
PRIVATE
GTest::gtest
GTest::gtest_main
Qt${QT_VERSION}::Core
${UT_QT_LIBS}
${UT_DTK_LIBS}
${UT_EXTRA_LIBS}
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_link_libraries(${TARGET_NAME} PRIVATE gcov)
endif()
gtest_discover_tests(${TARGET_NAME} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
message(STATUS "UT: ${TARGET_NAME} configured")
endfunction()

# ---------------------------------------------------------------------------
# test_settings:Settings / CustemBackend / KeySequenceEdit(GUI 混合,offscreen)
# ---------------------------------------------------------------------------
add_ut_target(test_settings
SOURCES test_settings.cpp ${SETTINGS_SOURCES} ${UT_RESOURCES_QRC}
QT_LIBS Qt${QT_VERSION}::Gui Qt${QT_VERSION}::Widgets Qt${QT_VERSION}::Svg Qt${QT_VERSION}::Core5Compat Qt${QT_VERSION}::Test
DTK_LIBS Dtk${QT_VERSION}::Widget Dtk${QT_VERSION}::Core
)

# ---------------------------------------------------------------------------
# test_config:Config(DConfig stub + iconv 检测)
# ---------------------------------------------------------------------------
add_ut_target(test_config
SOURCES test_config.cpp ${CONFIG_SOURCES}
QT_LIBS Qt${QT_VERSION}::Gui
DTK_LIBS Dtk${QT_VERSION}::Core
)

# ---------------------------------------------------------------------------
# test_utils:Utils(含 Settings 依赖,GUI offscreen)
# ---------------------------------------------------------------------------
add_ut_target(test_utils
SOURCES test_utils.cpp ${UTILS_SOURCES} ${SETTINGS_SOURCES} ${UT_RESOURCES_QRC}
QT_LIBS Qt${QT_VERSION}::Gui Qt${QT_VERSION}::Widgets Qt${QT_VERSION}::Svg Qt${QT_VERSION}::DBus Qt${QT_VERSION}::Core5Compat Qt${QT_VERSION}::Test
DTK_LIBS Dtk${QT_VERSION}::Widget Dtk${QT_VERSION}::Core
EXTRA_LIBS KF6::Codecs
)

# ---------------------------------------------------------------------------
# test_urlinfo:UrlInfo(header-only,Core 即可)
# ---------------------------------------------------------------------------
add_ut_target(test_urlinfo
SOURCES test_urlinfo.cpp ${URLINFO_SOURCES}
QT_LIBS Qt${QT_VERSION}::Gui Qt${QT_VERSION}::Widgets Qt${QT_VERSION}::Svg Qt${QT_VERSION}::DBus Qt${QT_VERSION}::Core5Compat
DTK_LIBS Dtk${QT_VERSION}::Widget Dtk${QT_VERSION}::Core
EXTRA_LIBS KF6::Codecs
)

# ---------------------------------------------------------------------------
# test_eventlog:Eventlogutils(QLibrary stub,Core)
# ---------------------------------------------------------------------------
add_ut_target(test_eventlog
SOURCES test_eventlog.cpp ${EVENTLOG_SOURCES}
QT_LIBS
DTK_LIBS
)
46 changes: 46 additions & 0 deletions tests/common/cov_report.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
# B2 批次 lcov 函数覆盖率统计(按测试目标隔离对象目录)
# 用法: cov_report.sh <target_name> [source_file_filter]
# source_file_filter: 可选,按源文件名过滤(如 utils.cpp / settings.cpp / urlinfo.h)
set -u
TARGET="$1"
FILTER="${2:-}"
BD=/home/uos/work/ut/deepin-editor/build
OBJDIR="$BD/tests/common/CMakeFiles/${TARGET}.dir"
lcov --capture --directory "$OBJDIR" -o "/tmp/b2_${TARGET}.info" -q 2>/dev/null
lcov --extract "/tmp/b2_${TARGET}.info" '*/src/common/*' -o "/tmp/b2_${TARGET}_f.info" -q 2>/dev/null
python3 - "/tmp/b2_${TARGET}_f.info" "$FILTER" <<'PYEOF'
import re, sys
info = open(sys.argv[1]).read()
filt = sys.argv[2] if len(sys.argv) > 2 else ""

# 按 SF 分段
per_file = {}
cur = None
for line in info.splitlines():
if line.startswith("SF:"):
cur = line[3:]
per_file[cur] = {}
elif line.startswith("FNDA:") and cur is not None:
cnt, name = line[5:].split(",", 1)
per_file[cur][name] = max(per_file[cur].get(name, 0), int(cnt))

total = hit = 0
uncovered = []
for sf, fns in per_file.items():
if filt and not sf.endswith("/" + filt) and filt not in sf.split("/")[-1]:
continue
for name, cnt in fns.items():
total += 1
if cnt > 0:
hit += 1
else:
uncovered.append(f"{sf.split('/')[-1]}: {name}")

if total == 0:
print("NO_FUNCTION_DATA")
sys.exit(1)
print(f"FUNCTION_COVERAGE[{filt or 'all'}]: {100.0*hit/total:.1f}% ({hit}/{total})")
for u in uncovered:
print("UNCOVERED:", u)
PYEOF
Loading
Loading