Skip to content
Draft
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
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ TEST = \
${GOPKG_PREFIX}/clipboard1 \
${GOPKG_PREFIX}/clipboard1/mocks \
${GOPKG_PREFIX}/common/bluetooth \
${GOPKG_PREFIX}/common/cpuinfo \
${GOPKG_PREFIX}/common/scale \
${GOPKG_PREFIX}/common/dsync \
${GOPKG_PREFIX}/common/sessionmsg \
${GOPKG_PREFIX}/dbus \
Expand All @@ -51,6 +53,7 @@ TEST = \
${GOPKG_PREFIX}/grub_common \
${GOPKG_PREFIX}/grub_gfx \
${GOPKG_PREFIX}/housekeeping \
${GOPKG_PREFIX}/image_effect1 \
${GOPKG_PREFIX}/inputdevices1 \
${GOPKG_PREFIX}/inputdevices1/iso639 \
${GOPKG_PREFIX}/keybinding1 \
Expand Down Expand Up @@ -88,6 +91,9 @@ TEST = \
${GOPKG_PREFIX}/x_event_monitor1 \
${GOPKG_PREFIX}/bin/default-file-manager \
${GOPKG_PREFIX}/display1 \
${GOPKG_PREFIX}/display1/brightness \
${GOPKG_PREFIX}/display1/utils \
${GOPKG_PREFIX}/common/fileutil \
#${GOPKG_PREFIX}/timedate1/zoneinfo \

BINARIES = \
Expand Down Expand Up @@ -158,7 +164,7 @@ build: prepare out/bin/default-terminal out/bin/default-file-manager out/bin/des
test: prepare
env GOPATH="${CURDIR}/${GOPATH_DIR}:${GOPATH}" go test -v ${TEST}
test-coverage: prepare
env GOPATH="${CURDIR}/${GOPATH_DIR}:${GOPATH}" go test -cover -v ./... | awk '$$2 ~ "_${CURDIR}" {print $$2","$$5}' | sed "s:${CURDIR}::g" | sed 's/files\]/0\.0%/g' > coverage.csv
env GOPATH="${CURDIR}/${GOPATH_DIR}:${GOPATH}" go test -cover -v ${TEST} | awk '$$2 ~ "${GOPKG_PREFIX}" {print $$2","$$5}' | sed "s:${GOPKG_PREFIX}/::g" | sed 's/files\]/0\.0%/g' > coverage.csv

print_gopath: prepare
GOPATH="${CURDIR}/${GOPATH_DIR}:${GOPATH}"
Expand Down
112 changes: 112 additions & 0 deletions calltrace/calltrace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

package calltrace

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestStoi64(t *testing.T) {
assert.Equal(t, int64(123), stoi64("123"))
assert.Equal(t, int64(0), stoi64(""))
assert.Equal(t, int64(0), stoi64("abc"))
assert.Equal(t, int64(-42), stoi64("-42"))
}

func TestCpuTimeInfo_Total(t *testing.T) {
info := &cpuTimeInfo{
utime: 10,
stime: 20,
cutime: 5,
cstime: 3,
nice: 2,
start: 100,
hertz: 100,
}
assert.Equal(t, int64(40), info.Total())
}

func TestCpuTimeInfo_Total_Zero(t *testing.T) {
info := &cpuTimeInfo{}
assert.Equal(t, int64(0), info.Total())
}

func TestCpuTimeInfo_Percentage(t *testing.T) {
// start=200, hertz=100 → start/hertz=2, seconds = uptime - 2
// Total=100, Total/hertz=1, Percentage = 100 * (1 / (uptime-2))
info := &cpuTimeInfo{
utime: 50,
stime: 50,
cutime: 0,
cstime: 0,
nice: 0,
start: 200,
hertz: 100,
}
// uptime comes from /proc/uptime; can't control, but we can verify
// the formula doesn't panic and returns a float (likely 0 in test env
// because /proc/uptime read may fail or return 0 → division by zero).
// Instead test the pure arithmetic directly:
assert.Equal(t, int64(100), info.Total())
}

func TestGetInterge(t *testing.T) {
// format: "RssAnon: 100 kB" → split → ["RssAnon:", "100", "kB"]
v, err := getInterge("RssAnon: 100 kB")
assert.NoError(t, err)
assert.Equal(t, int64(100), v)

v, err = getInterge("VmPTE: 8 kB")
assert.NoError(t, err)
assert.Equal(t, int64(8), v)
}

func TestGetInterge_BadFormat(t *testing.T) {
// 只有两个字段(不足 3 个)→ error
_, err := getInterge("VmPTE: 100")
assert.Error(t, err)

// 中间不是数字 → error
_, err = getInterge("VmPTE: abc kB")
assert.Error(t, err)
}

func TestSumMemByFile(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "status")
content := "Name:\ttest\n" +
"RssAnon: 100 kB\n" +
"VmPTE: 8 kB\n" +
"VmPMD: 2 kB\n" +
"Other: 999 kB\n"
require.NoError(t, os.WriteFile(path, []byte(content), 0600))

total, err := sumMemByFile(path)
assert.NoError(t, err)
// 100 + 8 + 2 = 110
assert.Equal(t, int64(110), total)
}

func TestSumMemByFile_MissingFields(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "status")
// 只有 RssAnon,缺 VmPTE/VmPMD → 只累加 RssAnon
content := "RssAnon: 50 kB\n"
require.NoError(t, os.WriteFile(path, []byte(content), 0600))

total, err := sumMemByFile(path)
assert.NoError(t, err)
assert.Equal(t, int64(50), total)
}

func TestSumMemByFile_NonExistent(t *testing.T) {
_, err := sumMemByFile("/nonexistent/path/to/status")
assert.Error(t, err)
}
126 changes: 126 additions & 0 deletions common/fileutil/fileutil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

package fileutil

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestSafeReadFile_RegularFile(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "data.txt")
content := []byte("hello dde-daemon")
require.NoError(t, os.WriteFile(path, content, 0600))

got, err := SafeReadFile(path)
assert.NoError(t, err)
assert.Equal(t, content, got)
}

func TestSafeReadFile_NonExistent(t *testing.T) {
dir := t.TempDir()
_, err := SafeReadFile(filepath.Join(dir, "missing"))
assert.Error(t, err)
}

func TestSafeReadFile_SymlinkRejected(t *testing.T) {
dir := t.TempDir()
target := filepath.Join(dir, "target")
require.NoError(t, os.WriteFile(target, []byte("x"), 0600))
link := filepath.Join(dir, "link")
require.NoError(t, os.Symlink(target, link))

_, err := SafeReadFile(link)
assert.Error(t, err)
assert.Contains(t, err.Error(), "symlink")
}

func TestSafeReadFile_DirectoryRejected(t *testing.T) {
dir := t.TempDir()
// 目录不是普通文件,应被拒绝
_, err := SafeReadFile(dir)
assert.Error(t, err)
assert.Contains(t, err.Error(), "not a regular file")
}

func TestSafeWriteFile_CreateNew(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "new.txt")
content := []byte("fresh content")

err := SafeWriteFile(path, content, 0600)
assert.NoError(t, err)

// 权限:owner 读写位必置(用掩码校验,对仅清 group/other 位的 umask 稳健)
info, err := os.Stat(path)
require.NoError(t, err)
assert.True(t, info.Mode().IsRegular())
assert.Equal(t, os.FileMode(0600), info.Mode().Perm()&os.FileMode(0600))

got, err := SafeReadFile(path)
assert.NoError(t, err)
assert.Equal(t, content, got)
}

func TestSafeWriteFile_OverwriteRegular(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "exists.txt")
require.NoError(t, os.WriteFile(path, []byte("old"), 0600))

err := SafeWriteFile(path, []byte("new"), 0600)
assert.NoError(t, err)

got, err := SafeReadFile(path)
assert.NoError(t, err)
assert.Equal(t, []byte("new"), got)
}

func TestSafeWriteFile_SymlinkRejected(t *testing.T) {
dir := t.TempDir()
target := filepath.Join(dir, "target")
require.NoError(t, os.WriteFile(target, []byte("x"), 0600))
link := filepath.Join(dir, "link")
require.NoError(t, os.Symlink(target, link))

err := SafeWriteFile(link, []byte("y"), 0600)
assert.Error(t, err)
assert.Contains(t, err.Error(), "symlink")

// 被拒绝后,符号链接目标内容不应被改写
got, err := os.ReadFile(target)
require.NoError(t, err)
assert.Equal(t, []byte("x"), got)
}

func TestSafeWriteFile_DirectoryRejected(t *testing.T) {
// 目标已存在且为目录(非普通文件),写侧应拒绝,与读侧对称
dir := t.TempDir()
err := SafeWriteFile(dir, []byte("x"), 0600)
assert.Error(t, err)
assert.Contains(t, err.Error(), "not a regular file")
}

func TestSafeWriteFile_NonExistentParent(t *testing.T) {
dir := t.TempDir()
// 父目录不存在,O_CREAT|O_EXCL 创建应失败
err := SafeWriteFile(filepath.Join(dir, "sub", "file"), []byte("z"), 0600)
assert.Error(t, err)
}

func TestSafeWriteFile_RoundTrip(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "round.txt")
payload := []byte{0x00, 0x01, 0xFF, 'A', '\n', '\t'}

require.NoError(t, SafeWriteFile(path, payload, 0600))
got, err := SafeReadFile(path)
assert.NoError(t, err)
assert.Equal(t, payload, got)
}
Loading
Loading