mirror of
https://gitee.com/rulego/streamsql.git
synced 2026-08-01 08:56:32 +00:00
264 lines
5.9 KiB
Go
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)
|
|
}
|
|
}
|