Files
streamsql/functions/functions_conversion_test.go
T

264 lines
5.9 KiB
Go

package functions
import (
"testing"
"time"
)
func TestNewConversionFunctions(t *testing.T) {
tests := []struct {
name string
funcName string
args []any
want any
wantErr bool
}{
// convert_tz 函数测试
{
name: "convert_tz with time.Time",
funcName: "convert_tz",
args: []any{time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC), "Asia/Shanghai"},
want: time.Date(2023, 1, 1, 20, 0, 0, 0, time.FixedZone("CST", 8*3600)),
wantErr: false,
},
{
name: "convert_tz with string",
funcName: "convert_tz",
args: []any{"2023-01-01 12:00:00", "America/New_York"},
wantErr: false,
},
{
name: "convert_tz invalid timezone",
funcName: "convert_tz",
args: []any{time.Now(), "Invalid/Timezone"},
wantErr: true,
},
{
name: "convert_tz invalid time format",
funcName: "convert_tz",
args: []any{"invalid-time", "UTC"},
wantErr: true,
},
// to_seconds 函数测试
{
name: "to_seconds with time.Time",
funcName: "to_seconds",
args: []any{time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)},
want: int64(1672531200),
wantErr: false,
},
{
name: "to_seconds with string",
funcName: "to_seconds",
args: []any{"2023-01-01T00:00:00Z"},
want: int64(1672531200),
wantErr: false,
},
{
name: "to_seconds invalid time format",
funcName: "to_seconds",
args: []any{"invalid-time"},
wantErr: true,
},
// chr 函数测试
{
name: "chr valid ASCII code",
funcName: "chr",
args: []any{65},
want: "A",
wantErr: false,
},
{
name: "chr space character",
funcName: "chr",
args: []any{32},
want: " ",
wantErr: false,
},
{
name: "chr invalid code negative",
funcName: "chr",
args: []any{-1},
wantErr: true,
},
{
name: "chr invalid code too large",
funcName: "chr",
args: []any{128},
wantErr: true,
},
// trunc 函数测试
{
name: "trunc positive number",
funcName: "trunc",
args: []any{3.14159, 2},
want: 3.14,
wantErr: false,
},
// url_encode 函数测试
{
name: "url_encode basic",
funcName: "url_encode",
args: []any{"hello world"},
want: "hello+world",
wantErr: false,
},
{
name: "url_encode special chars",
funcName: "url_encode",
args: []any{"hello@world.com"},
want: "hello%40world.com",
wantErr: false,
},
{
name: "url_encode empty",
funcName: "url_encode",
args: []any{""},
want: "",
wantErr: false,
},
{
name: "url_encode nil",
funcName: "url_encode",
args: []any{nil},
wantErr: true,
},
// url_decode 函数测试
{
name: "url_decode basic",
funcName: "url_decode",
args: []any{"hello+world"},
want: "hello world",
wantErr: false,
},
{
name: "url_decode special chars",
funcName: "url_decode",
args: []any{"hello%40world.com"},
want: "hello@world.com",
wantErr: false,
},
{
name: "url_decode empty",
funcName: "url_decode",
args: []any{""},
want: "",
wantErr: false,
},
{
name: "url_decode nil",
funcName: "url_decode",
args: []any{nil},
wantErr: true,
},
{
name: "url_decode invalid",
funcName: "url_decode",
args: []any{"hello%ZZ"},
wantErr: true,
},
{
name: "trunc negative number",
funcName: "trunc",
args: []any{-3.14159, 3},
want: -3.141,
wantErr: false,
},
{
name: "trunc zero precision",
funcName: "trunc",
args: []any{3.14159, 0},
want: 3.0,
wantErr: false,
},
{
name: "trunc negative precision",
funcName: "trunc",
args: []any{3.14159, -1},
wantErr: true,
},
{
name: "trunc nil input returns error",
funcName: "trunc",
args: []any{nil, 2},
wantErr: true,
},
{
name: "trunc non-numeric input returns error",
funcName: "trunc",
args: []any{"abc", 2},
wantErr: true,
},
{
name: "trunc precision too large returns error",
funcName: "trunc",
args: []any{3.14, 400},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fn, exists := Get(tt.funcName)
if !exists {
t.Fatalf("Function %s not found", tt.funcName)
}
result, err := fn.Execute(nil, tt.args)
if (err != nil) != tt.wantErr {
t.Errorf("Execute() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
// 对于时间类型,需要特殊处理比较
if tt.funcName == "convert_tz" {
if resultTime, ok := result.(time.Time); ok {
if wantTime, ok := tt.want.(time.Time); ok {
// 比较时间戳而不是直接比较时间对象
if resultTime.Unix() != wantTime.Unix() {
t.Errorf("Execute() = %v, want %v", result, tt.want)
}
} else {
// 如果期望值不是时间类型,只检查结果是否为时间类型
if resultTime.IsZero() {
t.Errorf("Execute() returned zero time")
}
}
} else {
t.Errorf("Execute() result is not time.Time")
}
} else if tt.want != nil && result != tt.want {
t.Errorf("Execute() = %v, want %v", result, tt.want)
}
}
})
}
}
func TestCastIntRanges(t *testing.T) {
fn, ok := Get("cast")
if !ok {
t.Fatal("cast function not found")
}
// int32 overflow must error instead of silently wrapping.
if _, err := fn.Execute(&FunctionContext{}, []any{2147483648, "int32"}); err == nil {
t.Error(`cast(2147483648, "int32") expected error, got nil`)
}
// "int" returns int (not int32) on 64-bit platforms.
r, err := fn.Execute(&FunctionContext{}, []any{100, "int"})
if err != nil {
t.Errorf(`cast(100, "int") unexpected error: %v`, err)
}
if _, ok := r.(int); !ok {
t.Errorf(`cast(100, "int") returned %T, want int`, r)
}
}