- 替换 Beego 框架为 GoFrame v2 - 重构项目结构: controller/service/dao/middleware 分层 - 替换自定义 crons 包为 gcron - 模板从 views/ 迁移到 resource/template/ - 配置从 conf/app.conf 迁移到 config.yml - 数据库从 MySQL 切换为 SQLite (modernc.org/sqlite) - 移除 agent/ 远程执行器(待后续迁移) - 移除 crons/ 自定义定时器包 - 静态资源整理到 resource/static/
113 lines
3.0 KiB
Go
113 lines
3.0 KiB
Go
package dao
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestParsePage(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
pageNum int
|
|
pageSize int
|
|
wantOffset int
|
|
wantLimit int
|
|
}{
|
|
{"normal first page", 1, 20, 0, 20},
|
|
{"second page", 2, 20, 20, 20},
|
|
{"page 5", 5, 10, 40, 10},
|
|
{"page 0 treated as 1", 0, 20, 0, 20},
|
|
{"negative page treated as 1", -1, 20, 0, 20},
|
|
{"page size 0 defaults to 20", 1, 0, 0, 20},
|
|
{"negative page size defaults to 20", 1, -5, 0, 20},
|
|
{"page size capped at 1000", 1, 5000, 0, 1000},
|
|
{"page size exactly 1000", 1, 1000, 0, 1000},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
gotOffset, gotLimit := ParsePage(tt.pageNum, tt.pageSize)
|
|
if gotOffset != tt.wantOffset {
|
|
t.Errorf("ParsePage(%d, %d) offset = %d, want %d", tt.pageNum, tt.pageSize, gotOffset, tt.wantOffset)
|
|
}
|
|
if gotLimit != tt.wantLimit {
|
|
t.Errorf("ParsePage(%d, %d) limit = %d, want %d", tt.pageNum, tt.pageSize, gotLimit, tt.wantLimit)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParsePagePage3Size15(t *testing.T) {
|
|
offset, limit := ParsePage(3, 15)
|
|
if offset != 30 {
|
|
t.Errorf("offset = %d, want 30", offset)
|
|
}
|
|
if limit != 15 {
|
|
t.Errorf("limit = %d, want 15", limit)
|
|
}
|
|
}
|
|
|
|
// TestFilterLogic tests the filter pairing logic that buildFilters relies on.
|
|
// The actual buildFilters function requires a real gdb.DB connection, so we
|
|
// validate the K/V pairing semantics here directly.
|
|
func TestFilterLogic(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
filters []interface{}
|
|
wantOK int // expected number of valid (string, value) pairs
|
|
}{
|
|
{"nil filters", nil, 0},
|
|
{"empty filters", []interface{}{}, 0},
|
|
{"single pair", []interface{}{"status", 1}, 1},
|
|
{"two pairs", []interface{}{"status", 1, "group_id", 5}, 2},
|
|
{"odd number of args", []interface{}{"status", 1, "group_id"}, 1},
|
|
{"non-string key", []interface{}{123, "value"}, 0},
|
|
{"mixed valid and invalid", []interface{}{"status", 1, 123, "value", "group_id", 5}, 2},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
pairs := 0
|
|
if tt.filters != nil {
|
|
for k := 0; k < len(tt.filters); k += 2 {
|
|
if k+1 < len(tt.filters) {
|
|
if _, ok := tt.filters[k].(string); ok {
|
|
pairs++
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if pairs != tt.wantOK {
|
|
t.Errorf("有效过滤对数量 = %d, 期望 %d", pairs, tt.wantOK)
|
|
}
|
|
})
|
|
}
|
|
|
|
// Also verify that the logic never panics on edge cases
|
|
edgeCases := []struct {
|
|
name string
|
|
filters []interface{}
|
|
}{
|
|
{"nil", nil},
|
|
{"empty", []interface{}{}},
|
|
{"odd length", []interface{}{"status", 1, "group_id"}},
|
|
{"non-string key", []interface{}{123, "value"}},
|
|
}
|
|
for _, ec := range edgeCases {
|
|
t.Run("no_panic_"+ec.name, func(t *testing.T) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
t.Errorf("unexpected panic: %v", r)
|
|
}
|
|
}()
|
|
if ec.filters == nil {
|
|
return
|
|
}
|
|
for k := 0; k < len(ec.filters); k += 2 {
|
|
if k+1 < len(ec.filters) {
|
|
if _, ok := ec.filters[k].(string); ok {
|
|
_ = ec.filters[k+1]
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|