This commit is contained in:
Joe
2026-01-16 15:49:34 +08:00
commit 550d3e1f42
380 changed files with 62024 additions and 0 deletions
+150
View File
@@ -0,0 +1,150 @@
package unit
import (
"net"
"testing"
"github.com/stretchr/testify/suite"
)
// IPMatcherTestSuite IP 匹配器测试套件
type IPMatcherTestSuite struct {
suite.Suite
}
func TestIPMatcherTestSuite(t *testing.T) {
suite.Run(t, new(IPMatcherTestSuite))
}
func (s *IPMatcherTestSuite) SetupTest() {
}
func (s *IPMatcherTestSuite) TearDownTest() {
}
// isIPInRange 检查 IP 是否在指定范围内
func isIPInRange(ip, startIP, endIP net.IP) bool {
ipBytes := ip.To4()
startBytes := startIP.To4()
endBytes := endIP.To4()
if ipBytes == nil || startBytes == nil || endBytes == nil {
return false
}
ipInt := uint32(ipBytes[0])<<24 | uint32(ipBytes[1])<<16 | uint32(ipBytes[2])<<8 | uint32(ipBytes[3])
startInt := uint32(startBytes[0])<<24 | uint32(startBytes[1])<<16 | uint32(startBytes[2])<<8 | uint32(startBytes[3])
endInt := uint32(endBytes[0])<<24 | uint32(endBytes[1])<<16 | uint32(endBytes[2])<<8 | uint32(endBytes[3])
return ipInt >= startInt && ipInt <= endInt
}
// TestIsIPInRange_InRange 测试 IP 在范围内
func (s *IPMatcherTestSuite) TestIsIPInRange_InRange() {
ip := net.ParseIP("192.168.1.50")
startIP := net.ParseIP("192.168.1.1")
endIP := net.ParseIP("192.168.1.100")
s.True(isIPInRange(ip, startIP, endIP))
}
// TestIsIPInRange_AtStart 测试 IP 在范围起点
func (s *IPMatcherTestSuite) TestIsIPInRange_AtStart() {
ip := net.ParseIP("192.168.1.1")
startIP := net.ParseIP("192.168.1.1")
endIP := net.ParseIP("192.168.1.100")
s.True(isIPInRange(ip, startIP, endIP))
}
// TestIsIPInRange_AtEnd 测试 IP 在范围终点
func (s *IPMatcherTestSuite) TestIsIPInRange_AtEnd() {
ip := net.ParseIP("192.168.1.100")
startIP := net.ParseIP("192.168.1.1")
endIP := net.ParseIP("192.168.1.100")
s.True(isIPInRange(ip, startIP, endIP))
}
// TestIsIPInRange_OutOfRange 测试 IP 超出范围
func (s *IPMatcherTestSuite) TestIsIPInRange_OutOfRange() {
ip := net.ParseIP("192.168.1.101")
startIP := net.ParseIP("192.168.1.1")
endIP := net.ParseIP("192.168.1.100")
s.False(isIPInRange(ip, startIP, endIP))
}
// TestIsIPInRange_BeforeRange 测试 IP 在范围之前
func (s *IPMatcherTestSuite) TestIsIPInRange_BeforeRange() {
ip := net.ParseIP("192.168.0.255")
startIP := net.ParseIP("192.168.1.1")
endIP := net.ParseIP("192.168.1.100")
s.False(isIPInRange(ip, startIP, endIP))
}
// TestIsIPInRange_InvalidIP 测试无效 IP
func (s *IPMatcherTestSuite) TestIsIPInRange_InvalidIP() {
startIP := net.ParseIP("192.168.1.1")
endIP := net.ParseIP("192.168.1.100")
s.False(isIPInRange(nil, startIP, endIP))
}
// TestCIDRMatch 测试 CIDR 匹配
func (s *IPMatcherTestSuite) TestCIDRMatch() {
tests := []struct {
name string
ip string
cidr string
match bool
}{
{"匹配 /24", "192.168.1.100", "192.168.1.0/24", true},
{"不匹配 /24", "192.168.2.1", "192.168.1.0/24", false},
{"/32 精确匹配", "192.168.1.1", "192.168.1.1/32", true},
{"/32 不匹配", "192.168.1.2", "192.168.1.1/32", false},
{"/16 匹配", "192.168.100.50", "192.168.0.0/16", true},
}
for _, tt := range tests {
s.Run(tt.name, func() {
ip := net.ParseIP(tt.ip)
_, ipNet, _ := net.ParseCIDR(tt.cidr)
if tt.match {
s.True(ipNet.Contains(ip))
} else {
s.False(ipNet.Contains(ip))
}
})
}
}
// TestIPParsing 测试 IP 解析
func (s *IPMatcherTestSuite) TestIPParsing() {
tests := []struct {
name string
ip string
valid bool
}{
{"有效 IPv4", "192.168.1.1", true},
{"有效 IPv4 边界", "255.255.255.255", true},
{"有效 IPv4 零", "0.0.0.0", true},
{"无效 IP", "invalid-ip", false},
{"空字符串", "", false},
{"超出范围", "256.1.1.1", false},
}
for _, tt := range tests {
s.Run(tt.name, func() {
ip := net.ParseIP(tt.ip)
if tt.valid {
s.NotNil(ip)
} else {
s.Nil(ip)
}
})
}
}
+16
View File
@@ -0,0 +1,16 @@
package unit
import (
"os"
"testing"
)
func TestMain(m *testing.M) {
// 单元测试不需要完整的应用初始化
// 如果需要数据库等资源,请在 tests/feature 中编写功能测试
// 执行测试
exit := m.Run()
os.Exit(exit)
}
+128
View File
@@ -0,0 +1,128 @@
package unit
import (
"testing"
"github.com/stretchr/testify/suite"
)
// PaginationTestSuite 分页测试套件
type PaginationTestSuite struct {
suite.Suite
}
func TestPaginationTestSuite(t *testing.T) {
suite.Run(t, new(PaginationTestSuite))
}
func (s *PaginationTestSuite) SetupTest() {
}
func (s *PaginationTestSuite) TearDownTest() {
}
// paginateSlice 模拟分页函数
func paginateSlice[T any](slice []T, page, pageSize int) ([]T, int64) {
total := int64(len(slice))
if total == 0 {
return []T{}, 0
}
start := (page - 1) * pageSize
end := start + pageSize
if start >= len(slice) {
return []T{}, total
}
if end > len(slice) {
end = len(slice)
}
return slice[start:end], total
}
// validatePagination 模拟分页参数验证
func validatePagination(page, pageSize int) (int, int) {
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 10
}
const maxPageSize = 100
if pageSize > maxPageSize {
pageSize = maxPageSize
}
return page, pageSize
}
// TestPaginateSlice_EmptySlice 测试空切片
func (s *PaginationTestSuite) TestPaginateSlice_EmptySlice() {
result, total := paginateSlice([]int{}, 1, 10)
s.Empty(result)
s.Equal(int64(0), total)
}
// TestPaginateSlice_FirstPage 测试第一页
func (s *PaginationTestSuite) TestPaginateSlice_FirstPage() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
result, total := paginateSlice(slice, 1, 3)
s.Equal([]int{1, 2, 3}, result)
s.Equal(int64(10), total)
}
// TestPaginateSlice_MiddlePage 测试中间页
func (s *PaginationTestSuite) TestPaginateSlice_MiddlePage() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
result, total := paginateSlice(slice, 2, 3)
s.Equal([]int{4, 5, 6}, result)
s.Equal(int64(10), total)
}
// TestPaginateSlice_LastPage 测试最后一页(不满)
func (s *PaginationTestSuite) TestPaginateSlice_LastPage() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
result, total := paginateSlice(slice, 4, 3)
s.Equal([]int{10}, result)
s.Equal(int64(10), total)
}
// TestPaginateSlice_OutOfRange 测试超出范围的页码
func (s *PaginationTestSuite) TestPaginateSlice_OutOfRange() {
slice := []int{1, 2, 3, 4, 5}
result, total := paginateSlice(slice, 10, 3)
s.Empty(result)
s.Equal(int64(5), total)
}
// TestValidatePagination 测试分页参数验证
func (s *PaginationTestSuite) TestValidatePagination() {
tests := []struct {
name string
page int
pageSize int
wantPage int
wantPageSize int
}{
{"正常值", 1, 10, 1, 10},
{"page 小于 1", 0, 10, 1, 10},
{"page 为负数", -5, 10, 1, 10},
{"pageSize 小于 1", 1, 0, 1, 10},
{"pageSize 超过最大值", 1, 200, 1, 100},
{"两者都异常", -1, -1, 1, 10},
}
for _, tt := range tests {
s.Run(tt.name, func() {
gotPage, gotPageSize := validatePagination(tt.page, tt.pageSize)
s.Equal(tt.wantPage, gotPage)
s.Equal(tt.wantPageSize, gotPageSize)
})
}
}
+25
View File
@@ -0,0 +1,25 @@
//go:build linux
// +build linux
package unit
import (
"fmt"
"strings"
"testing"
"github.com/goravel/framework/support/path"
"github.com/stretchr/testify/assert"
)
func TestPathResource(t *testing.T) {
resourcePath := path.Resource()
fmt.Println(resourcePath)
assert.True(t, strings.HasPrefix(resourcePath, "/"))
assert.True(t, strings.HasSuffix(resourcePath, "/resources"))
resourcePath = path.Resource("test.txt")
fmt.Println(resourcePath)
assert.True(t, strings.HasPrefix(resourcePath, "/"))
assert.True(t, strings.HasSuffix(resourcePath, "/resources/test.txt"))
}
+100
View File
@@ -0,0 +1,100 @@
package unit
import (
"crypto/sha256"
"encoding/hex"
"testing"
"github.com/stretchr/testify/suite"
)
// TokenServiceTestSuite Token 服务测试套件
type TokenServiceTestSuite struct {
suite.Suite
}
func TestTokenServiceTestSuite(t *testing.T) {
suite.Run(t, new(TokenServiceTestSuite))
}
// SetupTest 每个测试前执行
func (s *TokenServiceTestSuite) SetupTest() {
}
// TearDownTest 每个测试后执行
func (s *TokenServiceTestSuite) TearDownTest() {
}
// hashToken 模拟 TokenService 的哈希函数
func hashToken(token string) string {
hash := sha256.Sum256([]byte(token))
return hex.EncodeToString(hash[:])
}
// TestHashToken_NormalToken 测试正常 token 哈希
func (s *TokenServiceTestSuite) TestHashToken_NormalToken() {
token := "test-token-123"
result := hashToken(token)
s.Len(result, 64, "SHA256 应产生 64 个十六进制字符")
}
// TestHashToken_EmptyToken 测试空 token 哈希
func (s *TokenServiceTestSuite) TestHashToken_EmptyToken() {
token := ""
result := hashToken(token)
s.Len(result, 64, "空 token 也应产生 64 个十六进制字符")
}
// TestHashToken_Consistency 测试哈希一致性
func (s *TokenServiceTestSuite) TestHashToken_Consistency() {
token := "test-token"
result1 := hashToken(token)
result2 := hashToken(token)
s.Equal(result1, result2, "相同输入应产生相同输出")
}
// TestHashToken_Uniqueness 测试不同输入产生不同哈希
func (s *TokenServiceTestSuite) TestHashToken_Uniqueness() {
result1 := hashToken("token1")
result2 := hashToken("token2")
s.NotEqual(result1, result2, "不同输入应产生不同输出")
}
// TestHashToken_TableDriven 表格驱动测试
func (s *TokenServiceTestSuite) TestHashToken_TableDriven() {
tests := []struct {
name string
token string
wantLen int
}{
{"正常 token", "test-token-123", 64},
{"空 token", "", 64},
{"长 token", "this-is-a-very-long-token-that-should-still-work", 64},
{"特殊字符", "token@#$%^&*()", 64},
{"Unicode", "中文token测试", 64},
}
for _, tt := range tests {
s.Run(tt.name, func() {
got := hashToken(tt.token)
s.Len(got, tt.wantLen)
})
}
}
// TestGenerateRandomToken_Length 测试生成随机 token 的长度
func (s *TokenServiceTestSuite) TestGenerateRandomToken_Length() {
// 注意:这里无法直接测试 generateRandomToken,因为它是私有方法
// 但可以通过 CreateToken 间接测试
// 这个测试需要在 feature 测试中完成,因为需要数据库
}
// TestGenerateRandomToken_Uniqueness 测试生成的 token 唯一性
func (s *TokenServiceTestSuite) TestGenerateRandomToken_Uniqueness() {
// 注意:这个测试需要在 feature 测试中完成
// 因为需要数据库来创建 token 并验证唯一性
}
+203
View File
@@ -0,0 +1,203 @@
package unit
import (
"testing"
"github.com/stretchr/testify/suite"
)
// TreeServiceTestSuite 树形服务测试套件
type TreeServiceTestSuite struct {
suite.Suite
}
func TestTreeServiceTestSuite(t *testing.T) {
suite.Run(t, new(TreeServiceTestSuite))
}
func (s *TreeServiceTestSuite) SetupTest() {
}
func (s *TreeServiceTestSuite) TearDownTest() {
}
// TreeNode 测试用树形节点
type TreeNode struct {
ID uint
ParentID uint
Name string
Children []TreeNode
}
// buildTree 构建树形结构
func buildTree(nodes []TreeNode) []TreeNode {
if len(nodes) == 0 {
return []TreeNode{}
}
// 先创建所有节点的映射
nodeMap := make(map[uint]*TreeNode)
for i := range nodes {
nodes[i].Children = []TreeNode{}
nodeMap[nodes[i].ID] = &nodes[i]
}
// 构建父子关系
for i := range nodes {
if nodes[i].ParentID != 0 {
if parent, ok := nodeMap[nodes[i].ParentID]; ok {
parent.Children = append(parent.Children, nodes[i])
}
}
}
// 收集根节点(从 map 中获取,确保 Children 已更新)
var roots []TreeNode
for i := range nodes {
if nodes[i].ParentID == 0 {
roots = append(roots, *nodeMap[nodes[i].ID])
}
}
return roots
}
// flattenTree 展平树形结构
func flattenTree(nodes []TreeNode) []TreeNode {
var result []TreeNode
for _, node := range nodes {
result = append(result, node)
if len(node.Children) > 0 {
result = append(result, flattenTree(node.Children)...)
}
}
return result
}
// contains 检查切片是否包含元素
func contains(slice []uint, item uint) bool {
for _, v := range slice {
if v == item {
return true
}
}
return false
}
// uniqueUint 去重
func uniqueUint(slice []uint) []uint {
seen := make(map[uint]bool)
var result []uint
for _, v := range slice {
if !seen[v] {
seen[v] = true
result = append(result, v)
}
}
return result
}
// TestBuildTree_EmptyList 测试空列表
func (s *TreeServiceTestSuite) TestBuildTree_EmptyList() {
result := buildTree([]TreeNode{})
s.Empty(result)
}
// TestBuildTree_SingleRoot 测试单个根节点
func (s *TreeServiceTestSuite) TestBuildTree_SingleRoot() {
nodes := []TreeNode{
{ID: 1, ParentID: 0, Name: "Root"},
}
result := buildTree(nodes)
s.Len(result, 1)
s.Equal("Root", result[0].Name)
}
// TestBuildTree_MultipleRoots 测试多个根节点
func (s *TreeServiceTestSuite) TestBuildTree_MultipleRoots() {
nodes := []TreeNode{
{ID: 1, ParentID: 0, Name: "Root1"},
{ID: 2, ParentID: 0, Name: "Root2"},
{ID: 3, ParentID: 0, Name: "Root3"},
}
result := buildTree(nodes)
s.Len(result, 3)
}
// TestBuildTree_ParentChild 测试父子关系
func (s *TreeServiceTestSuite) TestBuildTree_ParentChild() {
nodes := []TreeNode{
{ID: 1, ParentID: 0, Name: "Root"},
{ID: 2, ParentID: 1, Name: "Child1"},
{ID: 3, ParentID: 1, Name: "Child2"},
{ID: 4, ParentID: 2, Name: "Grandchild"},
}
result := buildTree(nodes)
s.Len(result, 1, "应该只有 1 个根节点")
s.Len(result[0].Children, 2, "根节点应该有 2 个子节点")
}
// TestFlattenTree 测试树形展平
func (s *TreeServiceTestSuite) TestFlattenTree() {
tree := []TreeNode{
{
ID: 1,
Name: "Root",
Children: []TreeNode{
{ID: 2, Name: "Child1"},
{ID: 3, Name: "Child2"},
},
},
}
result := flattenTree(tree)
s.Len(result, 3)
s.Equal("Root", result[0].Name)
s.Equal("Child1", result[1].Name)
s.Equal("Child2", result[2].Name)
}
// TestContains 测试 contains 函数
func (s *TreeServiceTestSuite) TestContains() {
tests := []struct {
name string
slice []uint
item uint
want bool
}{
{"空切片", []uint{}, 1, false},
{"存在的元素", []uint{1, 2, 3}, 2, true},
{"不存在的元素", []uint{1, 2, 3}, 4, false},
{"单元素存在", []uint{5}, 5, true},
}
for _, tt := range tests {
s.Run(tt.name, func() {
s.Equal(tt.want, contains(tt.slice, tt.item))
})
}
}
// TestUniqueUint 测试去重函数
func (s *TreeServiceTestSuite) TestUniqueUint() {
tests := []struct {
name string
slice []uint
want int // 期望的长度
}{
{"空切片", []uint{}, 0},
{"无重复", []uint{1, 2, 3}, 3},
{"有重复", []uint{1, 2, 2, 3, 3, 3}, 3},
{"全部重复", []uint{5, 5, 5}, 1},
}
for _, tt := range tests {
s.Run(tt.name, func() {
got := uniqueUint(tt.slice)
s.Len(got, tt.want)
})
}
}