github.com/influxdata/influxdb/v2@v2.7.6/influxql/query/math_test.go (about) 1 package query_test 2 3 import ( 4 "math" 5 "testing" 6 7 "github.com/influxdata/influxdb/v2/influxql/query" 8 "github.com/influxdata/influxql" 9 ) 10 11 func TestMath_TypeMapper(t *testing.T) { 12 for _, tt := range []struct { 13 s string 14 typ influxql.DataType 15 err bool 16 }{ 17 {s: `abs(f::float)`, typ: influxql.Float}, 18 {s: `abs(i::integer)`, typ: influxql.Integer}, 19 {s: `abs(u::unsigned)`, typ: influxql.Unsigned}, 20 {s: `abs(s::string)`, err: true}, 21 {s: `abs(b::boolean)`, err: true}, 22 {s: `sin(f::float)`, typ: influxql.Float}, 23 {s: `sin(i::integer)`, typ: influxql.Float}, 24 {s: `sin(u::unsigned)`, typ: influxql.Float}, 25 {s: `sin(s::string)`, err: true}, 26 {s: `sin(b::boolean)`, err: true}, 27 {s: `cos(f::float)`, typ: influxql.Float}, 28 {s: `cos(i::integer)`, typ: influxql.Float}, 29 {s: `cos(u::unsigned)`, typ: influxql.Float}, 30 {s: `cos(s::string)`, err: true}, 31 {s: `cos(b::boolean)`, err: true}, 32 {s: `tan(f::float)`, typ: influxql.Float}, 33 {s: `tan(i::integer)`, typ: influxql.Float}, 34 {s: `tan(u::unsigned)`, typ: influxql.Float}, 35 {s: `tan(s::string)`, err: true}, 36 {s: `tan(b::boolean)`, err: true}, 37 {s: `asin(f::float)`, typ: influxql.Float}, 38 {s: `asin(i::integer)`, err: true}, 39 {s: `asin(u::unsigned)`, err: true}, 40 {s: `asin(s::string)`, err: true}, 41 {s: `asin(b::boolean)`, err: true}, 42 {s: `acos(f::float)`, typ: influxql.Float}, 43 {s: `acos(i::integer)`, err: true}, 44 {s: `acos(u::unsigned)`, err: true}, 45 {s: `acos(s::string)`, err: true}, 46 {s: `acos(b::boolean)`, err: true}, 47 {s: `atan(f::float)`, typ: influxql.Float}, 48 {s: `atan(i::integer)`, typ: influxql.Float}, 49 {s: `atan(u::unsigned)`, typ: influxql.Float}, 50 {s: `atan(s::string)`, err: true}, 51 {s: `atan(b::boolean)`, err: true}, 52 {s: `atan2(y::float, x::float)`, typ: influxql.Float}, 53 {s: `atan2(y::integer, x::float)`, typ: influxql.Float}, 54 {s: `atan2(y::unsigned, x::float)`, typ: influxql.Float}, 55 {s: `atan2(y::string, x::float)`, err: true}, 56 {s: `atan2(y::boolean, x::float)`, err: true}, 57 {s: `atan2(y::float, x::float)`, typ: influxql.Float}, 58 {s: `atan2(y::float, x::integer)`, typ: influxql.Float}, 59 {s: `atan2(y::float, x::unsigned)`, typ: influxql.Float}, 60 {s: `atan2(y::float, x::string)`, err: true}, 61 {s: `atan2(y::float, x::boolean)`, err: true}, 62 {s: `exp(f::float)`, typ: influxql.Float}, 63 {s: `exp(i::integer)`, typ: influxql.Float}, 64 {s: `exp(u::unsigned)`, typ: influxql.Float}, 65 {s: `exp(s::string)`, err: true}, 66 {s: `exp(b::boolean)`, err: true}, 67 {s: `log(f::float)`, typ: influxql.Float}, 68 {s: `log(i::integer)`, typ: influxql.Float}, 69 {s: `log(u::unsigned)`, typ: influxql.Float}, 70 {s: `log(s::string)`, err: true}, 71 {s: `log(b::boolean)`, err: true}, 72 {s: `ln(f::float)`, typ: influxql.Float}, 73 {s: `ln(i::integer)`, typ: influxql.Float}, 74 {s: `ln(u::unsigned)`, typ: influxql.Float}, 75 {s: `ln(s::string)`, err: true}, 76 {s: `ln(b::boolean)`, err: true}, 77 {s: `log2(f::float)`, typ: influxql.Float}, 78 {s: `log2(i::integer)`, typ: influxql.Float}, 79 {s: `log2(u::unsigned)`, typ: influxql.Float}, 80 {s: `log2(s::string)`, err: true}, 81 {s: `log2(b::boolean)`, err: true}, 82 {s: `log10(f::float)`, typ: influxql.Float}, 83 {s: `log10(i::integer)`, typ: influxql.Float}, 84 {s: `log10(u::unsigned)`, typ: influxql.Float}, 85 {s: `log10(s::string)`, err: true}, 86 {s: `log10(b::boolean)`, err: true}, 87 {s: `sqrt(f::float)`, typ: influxql.Float}, 88 {s: `sqrt(i::integer)`, typ: influxql.Float}, 89 {s: `sqrt(u::unsigned)`, typ: influxql.Float}, 90 {s: `sqrt(s::string)`, err: true}, 91 {s: `sqrt(b::boolean)`, err: true}, 92 {s: `pow(y::float, x::float)`, typ: influxql.Float}, 93 {s: `pow(y::integer, x::float)`, typ: influxql.Float}, 94 {s: `pow(y::unsigned, x::float)`, typ: influxql.Float}, 95 {s: `pow(y::string, x::string)`, err: true}, 96 {s: `pow(y::boolean, x::boolean)`, err: true}, 97 {s: `pow(y::float, x::float)`, typ: influxql.Float}, 98 {s: `pow(y::float, x::integer)`, typ: influxql.Float}, 99 {s: `pow(y::float, x::unsigned)`, typ: influxql.Float}, 100 {s: `pow(y::float, x::string)`, err: true}, 101 {s: `pow(y::float, x::boolean)`, err: true}, 102 {s: `floor(f::float)`, typ: influxql.Float}, 103 {s: `floor(i::integer)`, typ: influxql.Integer}, 104 {s: `floor(u::unsigned)`, typ: influxql.Unsigned}, 105 {s: `floor(s::string)`, err: true}, 106 {s: `floor(b::boolean)`, err: true}, 107 {s: `ceil(f::float)`, typ: influxql.Float}, 108 {s: `ceil(i::integer)`, typ: influxql.Integer}, 109 {s: `ceil(u::unsigned)`, typ: influxql.Unsigned}, 110 {s: `ceil(s::string)`, err: true}, 111 {s: `ceil(b::boolean)`, err: true}, 112 {s: `round(f::float)`, typ: influxql.Float}, 113 {s: `round(i::integer)`, typ: influxql.Integer}, 114 {s: `round(u::unsigned)`, typ: influxql.Unsigned}, 115 {s: `round(s::string)`, err: true}, 116 {s: `round(b::boolean)`, err: true}, 117 } { 118 t.Run(tt.s, func(t *testing.T) { 119 expr := MustParseExpr(tt.s) 120 121 typmap := influxql.TypeValuerEval{ 122 TypeMapper: query.MathTypeMapper{}, 123 } 124 if got, err := typmap.EvalType(expr); err != nil { 125 if !tt.err { 126 t.Errorf("unexpected error: %s", err) 127 } 128 } else if tt.err { 129 t.Error("expected error") 130 } else if want := tt.typ; got != want { 131 t.Errorf("unexpected type:\n\t-: \"%s\"\n\t+: \"%s\"", want, got) 132 } 133 }) 134 } 135 } 136 137 func TestMathValuer_Call(t *testing.T) { 138 type values map[string]interface{} 139 for _, tt := range []struct { 140 s string 141 values values 142 exp interface{} 143 }{ 144 {s: `abs(f)`, values: values{"f": float64(2)}, exp: float64(2)}, 145 {s: `abs(f)`, values: values{"f": float64(-2)}, exp: float64(2)}, 146 {s: `abs(i)`, values: values{"i": int64(2)}, exp: int64(2)}, 147 {s: `abs(i)`, values: values{"i": int64(-2)}, exp: int64(2)}, 148 {s: `abs(u)`, values: values{"u": uint64(2)}, exp: uint64(2)}, 149 {s: `sin(f)`, values: values{"f": math.Pi / 2}, exp: math.Sin(math.Pi / 2)}, 150 {s: `sin(i)`, values: values{"i": int64(2)}, exp: math.Sin(2)}, 151 {s: `sin(u)`, values: values{"u": uint64(2)}, exp: math.Sin(2)}, 152 {s: `asin(f)`, values: values{"f": float64(0.5)}, exp: math.Asin(0.5)}, 153 {s: `cos(f)`, values: values{"f": math.Pi / 2}, exp: math.Cos(math.Pi / 2)}, 154 {s: `cos(i)`, values: values{"i": int64(2)}, exp: math.Cos(2)}, 155 {s: `cos(u)`, values: values{"u": uint64(2)}, exp: math.Cos(2)}, 156 {s: `acos(f)`, values: values{"f": float64(0.5)}, exp: math.Acos(0.5)}, 157 {s: `tan(f)`, values: values{"f": math.Pi / 2}, exp: math.Tan(math.Pi / 2)}, 158 {s: `tan(i)`, values: values{"i": int64(2)}, exp: math.Tan(2)}, 159 {s: `tan(u)`, values: values{"u": uint64(2)}, exp: math.Tan(2)}, 160 {s: `atan(f)`, values: values{"f": float64(2)}, exp: math.Atan(2)}, 161 {s: `atan(i)`, values: values{"i": int64(2)}, exp: math.Atan(2)}, 162 {s: `atan(u)`, values: values{"u": uint64(2)}, exp: math.Atan(2)}, 163 {s: `atan2(y, x)`, values: values{"y": float64(2), "x": float64(3)}, exp: math.Atan2(2, 3)}, 164 {s: `atan2(y, x)`, values: values{"y": int64(2), "x": int64(3)}, exp: math.Atan2(2, 3)}, 165 {s: `atan2(y, x)`, values: values{"y": uint64(2), "x": uint64(3)}, exp: math.Atan2(2, 3)}, 166 {s: `floor(f)`, values: values{"f": float64(2.5)}, exp: float64(2)}, 167 {s: `floor(i)`, values: values{"i": int64(2)}, exp: int64(2)}, 168 {s: `floor(u)`, values: values{"u": uint64(2)}, exp: uint64(2)}, 169 {s: `ceil(f)`, values: values{"f": float64(2.5)}, exp: float64(3)}, 170 {s: `ceil(i)`, values: values{"i": int64(2)}, exp: int64(2)}, 171 {s: `ceil(u)`, values: values{"u": uint64(2)}, exp: uint64(2)}, 172 {s: `round(f)`, values: values{"f": float64(2.4)}, exp: float64(2)}, 173 {s: `round(f)`, values: values{"f": float64(2.6)}, exp: float64(3)}, 174 {s: `round(i)`, values: values{"i": int64(2)}, exp: int64(2)}, 175 {s: `round(u)`, values: values{"u": uint64(2)}, exp: uint64(2)}, 176 {s: `exp(f)`, values: values{"f": float64(3)}, exp: math.Exp(3)}, 177 {s: `exp(i)`, values: values{"i": int64(3)}, exp: math.Exp(3)}, 178 {s: `exp(u)`, values: values{"u": uint64(3)}, exp: math.Exp(3)}, 179 {s: `log(f, 8)`, values: values{"f": float64(3)}, exp: math.Log(3) / math.Log(8)}, 180 {s: `log(i, 8)`, values: values{"i": int64(3)}, exp: math.Log(3) / math.Log(8)}, 181 {s: `log(u, 8)`, values: values{"u": uint64(3)}, exp: math.Log(3) / math.Log(8)}, 182 {s: `ln(f)`, values: values{"f": float64(3)}, exp: math.Log(3)}, 183 {s: `ln(i)`, values: values{"i": int64(3)}, exp: math.Log(3)}, 184 {s: `ln(u)`, values: values{"u": uint64(3)}, exp: math.Log(3)}, 185 {s: `log2(f)`, values: values{"f": float64(3)}, exp: math.Log2(3)}, 186 {s: `log2(i)`, values: values{"i": int64(3)}, exp: math.Log2(3)}, 187 {s: `log2(u)`, values: values{"u": uint64(3)}, exp: math.Log2(3)}, 188 {s: `log10(f)`, values: values{"f": float64(3)}, exp: math.Log10(3)}, 189 {s: `log10(i)`, values: values{"i": int64(3)}, exp: math.Log10(3)}, 190 {s: `log10(u)`, values: values{"u": uint64(3)}, exp: math.Log10(3)}, 191 {s: `sqrt(f)`, values: values{"f": float64(3)}, exp: math.Sqrt(3)}, 192 {s: `sqrt(i)`, values: values{"i": int64(3)}, exp: math.Sqrt(3)}, 193 {s: `sqrt(u)`, values: values{"u": uint64(3)}, exp: math.Sqrt(3)}, 194 {s: `pow(f, 2)`, values: values{"f": float64(4)}, exp: math.Pow(4, 2)}, 195 {s: `pow(i, 2)`, values: values{"i": int64(4)}, exp: math.Pow(4, 2)}, 196 {s: `pow(u, 2)`, values: values{"u": uint64(4)}, exp: math.Pow(4, 2)}, 197 } { 198 t.Run(tt.s, func(t *testing.T) { 199 expr := MustParseExpr(tt.s) 200 201 valuer := influxql.ValuerEval{ 202 Valuer: influxql.MultiValuer( 203 influxql.MapValuer(tt.values), 204 query.MathValuer{}, 205 ), 206 } 207 if got, want := valuer.Eval(expr), tt.exp; got != want { 208 t.Errorf("unexpected value: %v != %v", want, got) 209 } 210 }) 211 } 212 }