285 lines
6.1 KiB
Go
285 lines
6.1 KiB
Go
package starnet
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestUrlEncodeRaw(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "basic string with space",
|
|
input: "hello world",
|
|
expected: "hello%20world",
|
|
},
|
|
{
|
|
name: "special characters",
|
|
input: "hello world!@#$%^&*()_+-=~`",
|
|
expected: "hello%20world%21%40%23%24%25%5E%26%2A%28%29_%2B-%3D~%60",
|
|
},
|
|
{
|
|
name: "empty string",
|
|
input: "",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "chinese characters",
|
|
input: "你好世界",
|
|
expected: "%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := UrlEncodeRaw(tt.input)
|
|
if result != tt.expected {
|
|
t.Errorf("UrlEncodeRaw(%q) = %q; want %q", tt.input, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUrlEncode(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "space encoded as plus",
|
|
input: "hello world",
|
|
expected: "hello+world",
|
|
},
|
|
{
|
|
name: "special characters",
|
|
input: "hello world!@#$%^&*()_+-=~`",
|
|
expected: "hello+world%21%40%23%24%25%5E%26%2A%28%29_%2B-%3D~%60",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := UrlEncode(tt.input)
|
|
if result != tt.expected {
|
|
t.Errorf("UrlEncode(%q) = %q; want %q", tt.input, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUrlDecode(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
expectErr bool
|
|
}{
|
|
{
|
|
name: "basic decode",
|
|
input: "hello%20world",
|
|
expected: "hello world",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "plus to space",
|
|
input: "hello+world",
|
|
expected: "hello world",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "special characters",
|
|
input: "hello%20world%21%40%23%24%25%5E%26*%28%29_%2B-%3D~%60",
|
|
expected: "hello world!@#$%^&*()_+-=~`",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "invalid encoding",
|
|
input: "%zz",
|
|
expected: "",
|
|
expectErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result, err := UrlDecode(tt.input)
|
|
if tt.expectErr {
|
|
if err == nil {
|
|
t.Errorf("UrlDecode(%q) expected error, got nil", tt.input)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("UrlDecode(%q) unexpected error: %v", tt.input, err)
|
|
}
|
|
if result != tt.expected {
|
|
t.Errorf("UrlDecode(%q) = %q; want %q", tt.input, result, tt.expected)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildQuery(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input map[string]string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "single parameter",
|
|
input: map[string]string{
|
|
"key": "value",
|
|
},
|
|
expected: "key=value",
|
|
},
|
|
{
|
|
name: "empty map",
|
|
input: map[string]string{},
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "nil map",
|
|
input: nil,
|
|
expected: "",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := BuildQuery(tt.input)
|
|
if result != tt.expected {
|
|
t.Errorf("BuildQuery(%v) = %q; want %q", tt.input, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildPostForm(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input map[string]string
|
|
expected []byte
|
|
}{
|
|
{
|
|
name: "basic form",
|
|
input: map[string]string{
|
|
"key1": "value1",
|
|
},
|
|
expected: []byte("key1=value1"),
|
|
},
|
|
{
|
|
name: "empty map",
|
|
input: map[string]string{},
|
|
expected: []byte(""),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := BuildPostForm(tt.input)
|
|
if string(result) != string(tt.expected) {
|
|
t.Errorf("BuildPostForm(%v) = %v; want %v", tt.input, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidMethod(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
method string
|
|
expected bool
|
|
}{
|
|
{"GET", "GET", true},
|
|
{"POST", "POST", true},
|
|
{"PUT", "PUT", true},
|
|
{"DELETE", "DELETE", true},
|
|
{"PATCH", "PATCH", true},
|
|
{"OPTIONS", "OPTIONS", true},
|
|
{"HEAD", "HEAD", true},
|
|
{"TRACE", "TRACE", true},
|
|
{"CONNECT", "CONNECT", true},
|
|
{"invalid with space", "GET POST", false},
|
|
{"invalid with special char", "GET<>", false},
|
|
{"empty", "", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := validMethod(tt.method)
|
|
if result != tt.expected {
|
|
t.Errorf("validMethod(%q) = %v; want %v", tt.method, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCloneCookies_FullFields(t *testing.T) {
|
|
expire := time.Now().Add(2 * time.Hour)
|
|
|
|
src := []*http.Cookie{
|
|
{
|
|
Name: "sid",
|
|
Value: "abc123",
|
|
Path: "/",
|
|
Domain: "example.com",
|
|
Expires: expire,
|
|
RawExpires: expire.UTC().Format(time.RFC1123),
|
|
MaxAge: 3600,
|
|
Secure: true,
|
|
HttpOnly: true,
|
|
SameSite: http.SameSiteLaxMode,
|
|
Raw: "sid=abc123; Path=/; HttpOnly",
|
|
Unparsed: []string{"Priority=High", "Partitioned"},
|
|
},
|
|
}
|
|
|
|
got := cloneCookies(src)
|
|
if got == nil || len(got) != 1 {
|
|
t.Fatalf("cloneCookies() len=%v; want 1", len(got))
|
|
}
|
|
|
|
// 指针应不同(不是浅拷贝)
|
|
if got[0] == src[0] {
|
|
t.Fatal("cookie pointer should be different (deep copy expected)")
|
|
}
|
|
|
|
// 字段值应一致
|
|
s := src[0]
|
|
g := got[0]
|
|
if g.Name != s.Name ||
|
|
g.Value != s.Value ||
|
|
g.Path != s.Path ||
|
|
g.Domain != s.Domain ||
|
|
!g.Expires.Equal(s.Expires) ||
|
|
g.RawExpires != s.RawExpires ||
|
|
g.MaxAge != s.MaxAge ||
|
|
g.Secure != s.Secure ||
|
|
g.HttpOnly != s.HttpOnly ||
|
|
g.SameSite != s.SameSite ||
|
|
g.Raw != s.Raw {
|
|
t.Fatalf("cloned cookie fields mismatch:\n got=%+v\n src=%+v", g, s)
|
|
}
|
|
|
|
// Unparsed 内容一致
|
|
if len(g.Unparsed) != len(s.Unparsed) {
|
|
t.Fatalf("Unparsed len=%d; want %d", len(g.Unparsed), len(s.Unparsed))
|
|
}
|
|
for i := range s.Unparsed {
|
|
if g.Unparsed[i] != s.Unparsed[i] {
|
|
t.Fatalf("Unparsed[%d]=%q; want %q", i, g.Unparsed[i], s.Unparsed[i])
|
|
}
|
|
}
|
|
|
|
// 验证 Unparsed 是深拷贝(修改源不影响目标)
|
|
src[0].Unparsed[0] = "Modified=Yes"
|
|
if got[0].Unparsed[0] == "Modified=Yes" {
|
|
t.Fatal("Unparsed should be deep-copied, but was affected by source mutation")
|
|
}
|
|
}
|