test(utils): 为 utils 包添加全面单元测试(覆盖率 4.6% → 预计 >70%)

添加三个新测试文件:

bytes_test.go - 字节/字符串零拷贝转换测试:
- TestB2s: nil 切片、空切片、ASCII、UTF-8、特殊字符
- TestB2s_ZeroAlloc: 验证内存共享(指针比较)
- TestS2b: 空字符串返回 nil、正常转换
- TestS2b_ZeroAlloc: 验证内存共享
- TestB2s_S2b_RoundTrip: 往返转换正确性,包括二进制数据

etag_test.go - ETag 生成测试:
- TestGenerateETag: 表驱动测试,零时间、大尺寸、负值
- TestGenerateETag_Format: 验证引号包裹的 hex-hex 格式
- TestGenerateETag_Deterministic: 相同输入产生相同输出
- TestGenerateETag_DifferentInputs: 不同输入产生不同输出

ipallowlist_test.go - IP 白名单测试:
- TestParseIPAllowList: nil、空、CIDR、单 IP、localhost、无效输入
- TestParseIPAllowList_Localhost: 验证 127.0.0.1/32 + ::1/128 展开
- TestParseIPAllowList_SingleIPv4/IPv6: /32 和 /128 自动转换
- TestParseCIDR/TestParseCIDR_Invalid: 有效/无效 CIDR 和单 IP
- TestIPInAllowList: 匹配/不匹配及边界情况
- TestParseIPAllowList_Integration: 端到端解析+检查
This commit is contained in:
xfy 2026-06-04 08:13:34 +08:00
parent d6ee721bc8
commit a836152836
3 changed files with 360 additions and 0 deletions

View File

@ -0,0 +1,95 @@
// Package utils 提供字节操作工具函数的测试。
//
// 该文件测试 B2s 和 S2b 函数,包括:
// - 空值处理
// - 正常值转换
// - 内存共享验证
//
// 作者xfy
package utils
import (
"testing"
"unsafe"
"github.com/stretchr/testify/assert"
)
func TestB2s(t *testing.T) {
tests := []struct {
name string
input []byte
want string
}{
{"nil_slice", nil, ""},
{"empty_slice", []byte{}, ""},
{"single_byte", []byte("a"), "a"},
{"ascii_string", []byte("hello world"), "hello world"},
{"utf8_string", []byte("你好世界"), "你好世界"},
{"special_chars", []byte("!@#$%^&*()"), "!@#$%^&*()"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := B2s(tt.input)
assert.Equal(t, tt.want, got)
})
}
}
func TestB2s_ZeroAlloc(t *testing.T) {
original := []byte("test")
s := B2s(original)
ptr := unsafe.StringData(s)
slicePtr := unsafe.SliceData(original)
assert.Equal(t, slicePtr, ptr, "B2s result should share memory with original slice")
}
func TestS2b(t *testing.T) {
tests := []struct {
name string
input string
want []byte
}{
{"empty_string", "", nil},
{"single_char", "a", []byte("a")},
{"ascii_string", "hello world", []byte("hello world")},
{"utf8_string", "你好世界", []byte("你好世界")},
{"special_chars", "!@#$%^&*()", []byte("!@#$%^&*()")},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := S2b(tt.input)
assert.Equal(t, tt.want, got)
})
}
}
func TestS2b_ZeroAlloc(t *testing.T) {
original := "test"
b := S2b(original)
strPtr := unsafe.StringData(original)
slicePtr := unsafe.SliceData(b)
assert.Equal(t, strPtr, slicePtr, "S2b result should share memory with original string")
}
func TestB2s_S2b_RoundTrip(t *testing.T) {
tests := []struct {
name string
value string
}{
{"empty", ""},
{"ascii", "hello"},
{"utf8", "你好"},
{"binary", "\x00\x01\xff"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := S2b(tt.value)
s := B2s(b)
assert.Equal(t, tt.value, s)
})
}
}

View File

@ -0,0 +1,86 @@
// Package utils 提供 ETag 生成工具函数的测试。
//
// 该文件测试 GenerateETag 函数,包括:
// - 正常参数生成
// - 零值参数
// - 大数值参数
// - 格式验证
//
// 作者xfy
package utils
import (
"fmt"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func makeETag(unix int64, size int64) string {
return fmt.Sprintf(`"%x-%x"`, unix, size)
}
func TestGenerateETag(t *testing.T) {
tests := []struct {
name string
modTime time.Time
size int64
}{
{"valid_time_and_size", time.Unix(1609459200, 0), 1024},
{"zero_time", time.Time{}, 100},
{"zero_size", time.Unix(1609459200, 0), 0},
{"large_size", time.Unix(1609459200, 0), 1<<62 - 1},
{"negative_size", time.Unix(1609459200, 0), -1},
{"negative_modtime", time.Unix(-1000, 0), 500},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := GenerateETag(tt.modTime, tt.size)
want := makeETag(tt.modTime.Unix(), tt.size)
assert.Equal(t, want, got)
})
}
}
func TestGenerateETag_Format(t *testing.T) {
etag := GenerateETag(time.Unix(1609459200, 0), 1024)
assert.True(t, strings.HasPrefix(etag, "\""), "ETag should start with a quote")
assert.True(t, strings.HasSuffix(etag, "\""), "ETag should end with a quote")
assert.Equal(t, byte('"'), etag[0])
assert.Equal(t, byte('"'), etag[len(etag)-1])
inner := strings.Trim(etag, "\"")
parts := strings.SplitN(inner, "-", 2)
require.Len(t, parts, 2, "inner ETag should have exactly one hyphen separator")
for _, part := range parts {
for _, c := range part {
assert.True(t, (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == '-',
"character %c in ETag part should be hex digit or minus sign", c)
}
}
}
func TestGenerateETag_Deterministic(t *testing.T) {
modTime := time.Unix(1700000000, 0)
size := int64(2048)
etag1 := GenerateETag(modTime, size)
etag2 := GenerateETag(modTime, size)
assert.Equal(t, etag1, etag2, "same inputs should produce identical ETags")
}
func TestGenerateETag_DifferentInputs(t *testing.T) {
t1 := time.Unix(1700000000, 0)
t2 := time.Unix(1700000001, 0)
assert.NotEqual(t, GenerateETag(t1, 100), GenerateETag(t2, 100),
"different modtimes should produce different ETags")
assert.NotEqual(t, GenerateETag(t1, 100), GenerateETag(t1, 200),
"different sizes should produce different ETags")
}

View File

@ -0,0 +1,179 @@
// Package utils 提供 IP 白名单工具函数的测试。
//
// 该文件测试 ParseIPAllowList、ParseCIDR、IPInAllowList 函数,包括:
// - 空列表处理
// - CIDR 格式解析
// - 单 IP 自动转换
// - localhost 特殊值
// - 无效输入处理
// - IP 匹配检查
//
// 作者xfy
package utils
import (
"net"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestParseIPAllowList(t *testing.T) {
tests := []struct {
name string
input []string
wantLen int
wantErr bool
}{
{"nil_input", nil, 0, false},
{"empty_input", []string{}, 0, false},
{"single_cidr_v4", []string{"192.168.1.0/24"}, 1, false},
{"single_cidr_v6", []string{"::1/128"}, 1, false},
{"single_ipv4", []string{"192.168.1.1"}, 1, false},
{"single_ipv6", []string{"::1"}, 1, false},
{"localhost_expansion", []string{"localhost"}, 2, false},
{"multiple_entries", []string{"192.168.1.0/24", "10.0.0.1", "::1/128"}, 3, false},
{"localhost_with_others", []string{"localhost", "10.0.0.0/8"}, 3, false},
{"invalid_entry", []string{"not-an-ip"}, 0, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := ParseIPAllowList(tt.input)
if tt.wantErr {
assert.Error(t, err)
return
}
require.NoError(t, err)
assert.Len(t, result, tt.wantLen)
})
}
}
func TestParseIPAllowList_Localhost(t *testing.T) {
result, err := ParseIPAllowList([]string{"localhost"})
require.NoError(t, err)
require.Len(t, result, 2)
assert.Equal(t, "127.0.0.1/32", result[0].String())
assert.Equal(t, "::1/128", result[1].String())
}
func TestParseIPAllowList_SingleIPv4(t *testing.T) {
result, err := ParseIPAllowList([]string{"192.168.1.100"})
require.NoError(t, err)
require.Len(t, result, 1)
assert.Equal(t, "192.168.1.100/32", result[0].String())
}
func TestParseIPAllowList_SingleIPv6(t *testing.T) {
result, err := ParseIPAllowList([]string{"2001:db8::1"})
require.NoError(t, err)
require.Len(t, result, 1)
assert.Equal(t, "2001:db8::1/128", result[0].String())
}
func TestParseCIDR(t *testing.T) {
tests := []struct {
name string
input string
want string
wantIP string
}{
{"cidr_v4", "192.168.1.0/24", "192.168.1.0/24", "192.168.1.0"},
{"cidr_v6", "::1/128", "::1/128", "::1"},
{"single_ipv4", "10.0.0.1", "10.0.0.1/32", "10.0.0.1"},
{"single_ipv6", "::1", "::1/128", "::1"},
{"slash16", "172.16.0.0/16", "172.16.0.0/16", "172.16.0.0"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
network, err := ParseCIDR(tt.input)
require.NoError(t, err)
assert.Equal(t, tt.want, network.String())
assert.Equal(t, tt.wantIP, network.IP.String())
})
}
}
func TestParseCIDR_Invalid(t *testing.T) {
tests := []struct {
name string
input string
}{
{"empty_string", ""},
{"invalid_ip", "not-an-ip"},
{"invalid_cidr", "192.168.1.0/33"},
{"invalid_cidr_v6", "::1/129"},
{"garbage", "hello/world"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := ParseCIDR(tt.input)
assert.Error(t, err)
})
}
}
func TestIPInAllowList(t *testing.T) {
_, v4Net, _ := net.ParseCIDR("192.168.1.0/24")
_, v6Net, _ := net.ParseCIDR("::1/128")
_, net10, _ := net.ParseCIDR("10.0.0.0/8")
allowList := []net.IPNet{*v4Net, *v6Net, *net10}
tests := []struct {
name string
ip string
wantMatch bool
}{
{"matching_v4_in_range", "192.168.1.100", true},
{"matching_v4_boundary_start", "192.168.1.0", true},
{"matching_v4_boundary_end", "192.168.1.255", true},
{"matching_v6_localhost", "::1", true},
{"matching_10_range", "10.50.0.1", true},
{"non_matching_v4", "172.16.0.1", false},
{"non_matching_v6", "2001:db8::1", false},
{"non_matching_nearby", "192.168.2.1", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ip := net.ParseIP(tt.ip)
require.NotNil(t, ip)
result := IPInAllowList(ip, allowList)
assert.Equal(t, tt.wantMatch, result)
})
}
}
func TestIPInAllowList_EmptyList(t *testing.T) {
ip := net.ParseIP("192.168.1.1")
require.NotNil(t, ip)
assert.False(t, IPInAllowList(ip, nil))
assert.False(t, IPInAllowList(ip, []net.IPNet{}))
}
func TestIPInAllowList_SingleEntry(t *testing.T) {
_, network, err := net.ParseCIDR("127.0.0.1/32")
require.NoError(t, err)
allowList := []net.IPNet{*network}
assert.True(t, IPInAllowList(net.ParseIP("127.0.0.1"), allowList))
assert.False(t, IPInAllowList(net.ParseIP("127.0.0.2"), allowList))
}
func TestParseIPAllowList_Integration(t *testing.T) {
result, err := ParseIPAllowList([]string{"192.168.1.0/24", "10.0.0.1", "localhost"})
require.NoError(t, err)
require.Len(t, result, 4)
assert.True(t, IPInAllowList(net.ParseIP("192.168.1.50"), result))
assert.True(t, IPInAllowList(net.ParseIP("10.0.0.1"), result))
assert.True(t, IPInAllowList(net.ParseIP("127.0.0.1"), result))
assert.True(t, IPInAllowList(net.ParseIP("::1"), result))
assert.False(t, IPInAllowList(net.ParseIP("8.8.8.8"), result))
}