// This is the file for UDF&UDAF binding from datafusion,
// including most test for those function(except ApproxMedian which datafusion didn't implement)
// check src/script/builtins/test.rs::run_builtin_fn_testcases() for more information
[
    // math expressions
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
            "pows": Var(
                ty: Int8,
                value: IntVec([0, -1, 3])
            )
        },
        script: r#"
from greptime import *
sqrt(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    1.0,
                    1.4142135623730951,
                    1.7320508075688772,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
sin(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    0.8414709848078965,
                    0.9092974268256817,
                    0.1411200080598672,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
cos(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    0.5403023058681398,
                    -0.4161468365471424,
                    -0.9899924966004454,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
tan(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    1.557407724654902,
                    -2.185039863261519,
                    -0.1425465430742778,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([0.3, 0.5, 1.0])
            )
        },
        script: r#"
from greptime import *
asin(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    0.30469265401539747,
                    0.5235987755982988,
                    1.5707963267948966,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([0.3, 0.5, 1.0])
            )
        },
        script: r#"
from greptime import *
acos(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    1.266103672779499,
                    1.0471975511965976,
                    0.0,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([0.3, 0.5, 1.1])
            )
        },
        script: r#"
from greptime import *
atan(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    0.2914567944778671,
                    0.46364760900080615,
                    0.8329812666744317,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([0.3, 0.5, 1.1])
            )
        },
        script: r#"
from greptime import *
floor(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    0.0,
                    0.0,
                    1.0,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([0.3, 0.5, 1.1])
            )
        },
        script: r#"
from greptime import *
ceil(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    1.0,
                    1.0,
                    2.0,
                ],
            ),
            ty: Float64
        ))
    ),
        TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([0.3, 0.5, 1.1])
            )
        },
        script: r#"
from greptime import *
round(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    0.0,
                    1.0,
                    1.0,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([-0.3, 0.5, -1.1])
            )
        },
        script: r#"
from greptime import *
abs(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    0.3,
                    0.5,
                    1.1,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([-0.3, 0.5, -1.1])
            )
        },
        script: r#"
from greptime import *
signum(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    -1.0,
                    1.0,
                    -1.0,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([0, 1.0, 2.0])
            )
        },
        script: r#"
from greptime import *
exp(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    1.0,
                    2.718281828459045,
                    7.38905609893065,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
ln(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    0.0,
                    0.6931471805599453,
                    1.0986122886681098,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
log2(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    0.0,
                    1.0,
                    1.584962500721156,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
log10(values)"#,
        expect: Ok((
            value: FloatVec(
                [
                    0.0,
                    0.3010299956639812,
                    0.47712125471966244,
                ],
            ),
            ty: Float64
        ))
    ),
    TestCase(
        input: {},
        script: r#"
from greptime import *
random(42)"#,
        expect: Ok((
            value: LenFloatVec(42),
            ty: Float64
        ))
    ),

// UDAF(Aggerate function)
// approx function is indeterministic
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: IntVec([1, 2, 2, 3])
            )
        },
        script: r#"
from greptime import *
approx_distinct(values)"#,
        expect: Ok((
            value: Int(3),
            ty: Float64
        ))
    ),
    // not impl in datafusion
    /*
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: IntVec([1, 2, 2, 3])
            )
        },
        script: r#"
from greptime import *
approx_median(values)"#,
        expect: Ok((
            value: Int(2),
            ty: Float64
        ))
    ),
    */
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: IntVec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
            )
        },
        script: r#"
from greptime import *
approx_percentile_cont(values, 0.6)"#,
        expect: Ok((
            value: Int(6),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
array_agg(values)"#,
        expect: Ok((
            value: FloatVec([1.0, 2.0, 3.0]),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
avg(values)"#,
        expect: Ok((
            value: Float(2.0),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "a": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
            "b": Var(
                ty: Float64,
                value: FloatVec([1.0, 0.0, -1.0])
            ),
        },
        script: r#"
from greptime import *
correlation(a, b)"#,
        expect: Ok((
            value: Float(-1.0),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: IntVec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
            )
        },
        script: r#"
from greptime import *
count(values)"#,
        expect: Ok((
            value: Int(10),
            ty: Int64
        ))
    ),
    TestCase(
        input: {
            "a": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
            "b": Var(
                ty: Float64,
                value: FloatVec([1.0, 0.0, -1.0])
            ),
        },
        script: r#"
from greptime import *
covariance(a, b)"#,
        expect: Ok((
            value: Float(-1.0),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "a": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
            "b": Var(
                ty: Float64,
                value: FloatVec([1.0, 0.0, -1.0])
            ),
        },
        script: r#"
from greptime import *
covariance_pop(a, b)"#,
        expect: Ok((
            value: Float(-0.6666666666666666),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: IntVec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
            )
        },
        script: r#"
from greptime import *
max(values)"#,
        expect: Ok((
            value: Int(10),
            ty: Int64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: IntVec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
            )
        },
        script: r#"
from greptime import *
min(values)"#,
        expect: Ok((
            value: Int(1),
            ty: Int64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
            )
        },
        script: r#"
from greptime import *
stddev(values)"#,
        expect: Ok((
            value: Float(3.0276503540974917),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
            )
        },
        script: r#"
from greptime import *
stddev_pop(values)"#,
        expect: Ok((
            value: Float(2.8722813232690143),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
            )
        },
        script: r#"
from greptime import *
sum(values)"#,
        expect: Ok((
            value: Float(55),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
            )
        },
        script: r#"
from greptime import *
variance(values)"#,
        expect: Ok((
            value: Float(9.166666666666666),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
            )
        },
        script: r#"
from greptime import *
variance_pop(values)"#,
        expect: Ok((
            value: Float(8.25),
            ty: Float64
        ))
    ),


// GrepTime's own UDF
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
            "pows": Var(
                ty: Int8,
                value: IntVec([0, -1, 3])
            )
        },
        script: r#"
from greptime import *
pow(values, pows)"#,
        expect: Ok((
            value: FloatVec([ 1.0, 0.5, 27.0]),
            ty: Float64
        ))
    ),

// Error handling test
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
            "pows": Var(
                ty: Int8,
                value: IntVec([0, 0, 0])
            )
        },
        script: r#"
from greptime import *
pow(values, 1)"#,
        expect: Ok((
            value: FloatVec([ 1.0, 2.0, 3.0]),
            ty: Float64
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
            "pows": Var(
                ty: Int8,
                value: IntVec([0, 0, 0])
            ),
            "num": Var(
                ty: Int64,
                value: Int(1)
            )
        },
        script: r#"
from greptime import *
pow(num, pows)"#,
        expect: Err("TypeError: Can't cast operand of type `int` into `vector`")
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
            "pows": Var(
                ty: Int8,
                value: IntVec([0, 0, 0])
            ),
            "num": Var(
                ty: Int64,
                value: Int(1)
            )
        },
        script: r#"
from greptime import *
asin(num, pows)"#,
        expect: Err("TypeError: Expected at most 1 arguments (2 given)")
    ),
    // Test Type Cast between float, int and bool
    TestCase(
        input: {
            "num": Var(
                ty: Int64,
                value: Int(1)
            )
        },
        script: r#"
from greptime import *
sin(num)"#,
        expect: Ok((
            ty: Float64,
            value: Float(0.8414709848078965)
        ))
    ),
    TestCase(
        input: {
            "num": Var(
                ty: Float64,
                value: Float(1.0)
            )
        },
        script: r#"
from greptime import *
sin(num)"#,
        expect: Ok((
            ty: Float64,
            value: Float(0.8414709848078965)
        ))
    ),
    TestCase(
        input: {},
        script: r#"
from greptime import *
sin(True)"#,
        expect: Ok((
            ty: Float64,
            value: Float(0.8414709848078965)
        ))
    ),
    TestCase(
        input: {
            "num": Var(
                ty: Boolean,
                value: Bool(false)
            )
        },
        script: r#"
from greptime import *
sin(num)"#,
        expect: Ok((
            ty: Float64,
            value: Float(0.0)
        ))
    ),
    // test if string returns error correctly
    TestCase(
        input: {
            "num": Var(
                ty: Boolean,
                value: Str("42")
            )
        },
        script: r#"
from greptime import *
sin(num)"#,
        expect: Err("TypeError: Can't cast type Utf8 to Float64")
    ),
    TestCase(
        input: {},
        script: r#"
from greptime import *
datetime("7d")"#,
        expect: Ok((
            ty: Int64,
            value: Int(604800)
        ))
    ),
    TestCase(
        input: {},
        script: r#"
from greptime import *
datetime("7dd")"#,
        expect: Err("Unknown time unit")
    ),
    TestCase(
        input: {},
        script: r#"
from greptime import *
datetime("d7")"#,
        expect: Err("Python Runtime error, error:")
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
            "ts": Var(
                ty: Int64,
                value: IntVec([0, 9, 20])
            ),
        },
        script: r#"
from greptime import *
interval(ts, values, 10, lambda x:sum(x))"#,
        expect: Ok((
            ty: Float64,
            value: FloatVec([3.0, 3.0])
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0, 4.0])
            ),
            "ts": Var(
                ty: Int64,
                value: IntVec([0, 9, 19, 20])
            ),
        },
        script: r#"
from greptime import *
interval(ts, values, 10, lambda x:last(x))"#,
        expect: Ok((
            ty: Float64,
            value: FloatVec([2.0, 4.0])
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0, 4.0])
            ),
            "ts": Var(
                ty: Int64,
                value: IntVec([0, 9, 19, 20])
            ),
        },
        script: r#"
from greptime import *
interval(ts, values, 10, lambda x:first(x))"#,
        expect: Ok((
            ty: Float64,
            value: FloatVec([1.0, 3.0])
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([])
            )
        },
        script: r#"
from greptime import *
prev(values)"#,
        expect: Ok((
            ty: Float64,
            value: FloatVec([1.0])
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
prev(values)"#,
        expect: Ok((
            ty: Float64,
            value: FloatVecWithNull([None, Some(1.0), Some(2.0)])
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
next(values)"#,
        expect: Ok((
            ty: Float64,
            value: FloatVecWithNull([Some(2.0), Some(3.0), None])
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
sum(prev(values))"#,
        expect: Ok((
            ty: Float64,
            value: Float(3.0)
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
            "pows": Var(
                ty: Float64,
                value: FloatVec([1.0, 2.0, 3.0])
            ),
        },
        script: r#"
from greptime import *
pow_gp(values, pows)"#,
        expect: Ok((
            ty: Float64,
            value: FloatVec([1.0, 4.0, 27.0])
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([-1.0, 2.0, 0.5])
            ),
            "lower": Var(
                ty: Float64,
                value: FloatVec([0.0, 0.0, 0.0])
            ),
            "upper": Var(
                ty: Float64,
                value: FloatVec([1.0, 1.0, 1.0])
            ),
        },
        script: r#"
from greptime import *
clip(values, lower, upper)"#,
        expect: Ok((
            ty: Float64,
            value: FloatVec([0.0, 1.0, 0.5])
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([-1.0, 2.0, 2.0, 0.5])
            )
        },
        script: r#"
from greptime import *
median(values)"#,
        expect: Ok((
            ty: Float64,
            value: Float(1.25)
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([-1.0, 2.0, 2.0, 0.5])
            )
        },
        script: r#"
from greptime import *
diff(values)"#,
        expect: Ok((
            ty: Float64,
            value: FloatVec([3.0, 0.0, -1.5])
        ))
    ),
    TestCase(
        input: {
            "values": Var(
                ty: Float64,
                value: FloatVec([-1.0, 2.0, 2.0, 0.0])
            )
        },
        script: r#"
from greptime import *
mean(values)"#,
        expect: Ok((
            ty: Float64,
            value: Float(0.75)
        ))
    ),
    TestCase(
        input: {
            "p": Var(
                ty: Float64,
                value: FloatVec([-1.0, 2.0])
            ),
            "x": Var(
                ty: Int64,
                value: IntVec([1, 1])
            )
        },
        script: r#"
from greptime import *
polyval(p, x)"#,
        expect: Ok((
            ty: Float64,
            value: Float(1.0)
        ))
    ),
    TestCase(
        input: {
            "p": Var(
                ty: Float64,
                value: FloatVec([-1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
argmax(p)"#,
        expect: Ok((
            ty: Int64,
            value: Int(2)
        ))
    ),
    TestCase(
        input: {
            "p": Var(
                ty: Float64,
                value: FloatVec([-1.0, 2.0, 3.0])
            )
        },
        script: r#"
from greptime import *
argmin(p)"#,
        expect: Ok((
            ty: Int64,
            value: Int(0)
        ))
    ),
    TestCase(
        input: {
            "x": Var(
                ty: Float64,
                value: FloatVec([-1.0, 2.0, 3.0])
            ),
            "p": Var(
                ty: Float64,
                value: FloatVec([0.5, 0.5, 0.5])
            )
        },
        script: r#"
from greptime import *
percentile(x, p)"#,
        expect: Ok((
            ty: Float64,
            value: Float(-0.97)
        ))
    ),
    TestCase(
        input: {
            "x": Var(
                ty: Float64,
                value: FloatVec([-1.0, 2.0, 3.0])
            ),
            "p": Var(
                ty: Float64,
                value: FloatVec([0.5, 0.5, 0.5])
            )
        },
        script: r#"
from greptime import *
scipy_stats_norm_cdf(x, p)"#,
        expect: Ok((
            ty: Float64,
            value: Float(0.3444602779022303)
        ))
    ),
    TestCase(
        input: {
            "x": Var(
                ty: Float64,
                value: FloatVec([-1.0, 2.0, 3.0])
            ),
            "p": Var(
                ty: Float64,
                value: FloatVec([0.5, 0.5, 0.5])
            )
        },
        script: r#"
from greptime import *
scipy_stats_norm_pdf(x, p)"#,
        expect: Ok((
            ty: Float64,
            value: Float(0.1768885735289059)
        ))
    )
]
