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:
parent
d6ee721bc8
commit
a836152836
95
internal/utils/bytes_test.go
Normal file
95
internal/utils/bytes_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
||||
86
internal/utils/etag_test.go
Normal file
86
internal/utils/etag_test.go
Normal 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")
|
||||
}
|
||||
179
internal/utils/ipallowlist_test.go
Normal file
179
internal/utils/ipallowlist_test.go
Normal 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))
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user