github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/logarithm_test.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package function 16 17 import ( 18 "fmt" 19 "math" 20 "testing" 21 22 "github.com/stretchr/testify/require" 23 "gopkg.in/src-d/go-errors.v1" 24 25 "github.com/dolthub/go-mysql-server/sql" 26 "github.com/dolthub/go-mysql-server/sql/expression" 27 "github.com/dolthub/go-mysql-server/sql/types" 28 ) 29 30 var epsilon = math.Nextafter(1, 2) - 1 31 32 func TestLn(t *testing.T) { 33 var testCases = []struct { 34 name string 35 rowType sql.Type 36 row sql.Row 37 expected interface{} 38 err *errors.Kind 39 }{ 40 {"Input value is null", types.Float64, sql.NewRow(nil), nil, nil}, 41 {"Input value is zero", types.Float64, sql.NewRow(0), nil, nil}, 42 {"Input value is negative", types.Float64, sql.NewRow(-1), nil, nil}, 43 {"Input value is valid string", types.Float64, sql.NewRow("2"), float64(0.6931471805599453), nil}, 44 {"Input value is invalid string", types.Float64, sql.NewRow("aaa"), nil, sql.ErrInvalidType}, 45 {"Input value is valid float64", types.Float64, sql.NewRow(3), float64(1.0986122886681096), nil}, 46 {"Input value is valid float32", types.Float32, sql.NewRow(float32(6)), float64(1.791759469228055), nil}, 47 {"Input value is valid int64", types.Int64, sql.NewRow(int64(8)), float64(2.0794415416798357), nil}, 48 {"Input value is valid int32", types.Int32, sql.NewRow(int32(10)), float64(2.302585092994046), nil}, 49 } 50 51 for _, tt := range testCases { 52 f := NewLogBaseFunc(math.E)(expression.NewGetField(0, tt.rowType, "", true)) 53 t.Run(tt.name, func(t *testing.T) { 54 t.Helper() 55 require := require.New(t) 56 result, err := f.Eval(sql.NewEmptyContext(), tt.row) 57 if tt.err != nil { 58 require.Error(err) 59 require.True(tt.err.Is(err)) 60 } else if tt.expected == nil { 61 require.NoError(err) 62 require.Nil(result) 63 require.True(f.IsNullable()) 64 } else { 65 require.NoError(err) 66 require.InEpsilonf(tt.expected, result, epsilon, fmt.Sprintf("Actual is: %v", result)) 67 } 68 }) 69 } 70 } 71 72 func TestLog2(t *testing.T) { 73 var testCases = []struct { 74 name string 75 rowType sql.Type 76 row sql.Row 77 expected interface{} 78 err *errors.Kind 79 }{ 80 {"Input value is null", types.Float64, sql.NewRow(nil), nil, nil}, 81 {"Input value is zero", types.Float64, sql.NewRow(0), nil, nil}, 82 {"Input value is negative", types.Float64, sql.NewRow(-1), nil, nil}, 83 {"Input value is valid string", types.Float64, sql.NewRow("2"), float64(1), nil}, 84 {"Input value is invalid string", types.Float64, sql.NewRow("aaa"), nil, sql.ErrInvalidType}, 85 {"Input value is valid float64", types.Float64, sql.NewRow(3), float64(1.5849625007211563), nil}, 86 {"Input value is valid float32", types.Float32, sql.NewRow(float32(6)), float64(2.584962500721156), nil}, 87 {"Input value is valid int64", types.Int64, sql.NewRow(int64(8)), float64(3), nil}, 88 {"Input value is valid int32", types.Int32, sql.NewRow(int32(10)), float64(3.321928094887362), nil}, 89 } 90 91 for _, tt := range testCases { 92 f := NewLogBaseFunc(float64(2))(expression.NewGetField(0, tt.rowType, "", true)) 93 t.Run(tt.name, func(t *testing.T) { 94 t.Helper() 95 require := require.New(t) 96 result, err := f.Eval(sql.NewEmptyContext(), tt.row) 97 if tt.err != nil { 98 require.Error(err) 99 require.True(tt.err.Is(err)) 100 } else if tt.expected == nil { 101 require.NoError(err) 102 require.Nil(result) 103 require.True(f.IsNullable()) 104 } else { 105 require.NoError(err) 106 require.InEpsilonf(tt.expected, result, epsilon, fmt.Sprintf("Actual is: %v", result)) 107 } 108 }) 109 } 110 } 111 112 func TestLog10(t *testing.T) { 113 var testCases = []struct { 114 name string 115 rowType sql.Type 116 row sql.Row 117 expected interface{} 118 err *errors.Kind 119 }{ 120 {"Input value is null", types.Float64, sql.NewRow(0), nil, nil}, 121 {"Input value is zero", types.Float64, sql.NewRow(0), nil, nil}, 122 {"Input value is negative", types.Float64, sql.NewRow(-1), nil, nil}, 123 {"Input value is valid string", types.Float64, sql.NewRow("2"), float64(0.3010299956639812), nil}, 124 {"Input value is invalid string", types.Float64, sql.NewRow("aaa"), nil, sql.ErrInvalidType}, 125 {"Input value is valid float64", types.Float64, sql.NewRow(3), float64(0.4771212547196624), nil}, 126 {"Input value is valid float32", types.Float32, sql.NewRow(float32(6)), float64(0.7781512503836436), nil}, 127 {"Input value is valid int64", types.Int64, sql.NewRow(int64(8)), float64(0.9030899869919435), nil}, 128 {"Input value is valid int32", types.Int32, sql.NewRow(int32(10)), float64(1), nil}, 129 } 130 131 for _, tt := range testCases { 132 f := NewLogBaseFunc(float64(10))(expression.NewGetField(0, tt.rowType, "", true)) 133 t.Run(tt.name, func(t *testing.T) { 134 t.Helper() 135 require := require.New(t) 136 result, err := f.Eval(sql.NewEmptyContext(), tt.row) 137 if tt.err != nil { 138 require.Error(err) 139 require.True(tt.err.Is(err)) 140 } else if tt.expected == nil { 141 require.NoError(err) 142 require.Nil(result) 143 require.True(f.IsNullable()) 144 } else { 145 require.NoError(err) 146 require.InEpsilonf(tt.expected, result, epsilon, fmt.Sprintf("Actual is: %v", result)) 147 } 148 }) 149 } 150 } 151 152 func TestLogInvalidArguments(t *testing.T) { 153 _, err := NewLog() 154 require.True(t, sql.ErrInvalidArgumentNumber.Is(err)) 155 156 _, err = NewLog( 157 expression.NewLiteral(1, types.Float64), 158 expression.NewLiteral(1, types.Float64), 159 expression.NewLiteral(1, types.Float64), 160 ) 161 require.True(t, sql.ErrInvalidArgumentNumber.Is(err)) 162 } 163 164 func TestLog(t *testing.T) { 165 var testCases = []struct { 166 name string 167 input []sql.Expression 168 expected interface{} 169 err *errors.Kind 170 }{ 171 {"Input base is 1", []sql.Expression{expression.NewLiteral(float64(1), types.Float64), expression.NewLiteral(float64(10), types.Float64)}, nil, nil}, 172 {"Input base is nil", []sql.Expression{expression.NewLiteral(nil, types.Float64), expression.NewLiteral(float64(10), types.Float64)}, nil, nil}, 173 {"Input base is zero", []sql.Expression{expression.NewLiteral(float64(0), types.Float64), expression.NewLiteral(float64(10), types.Float64)}, nil, nil}, 174 {"Input base is negative", []sql.Expression{expression.NewLiteral(float64(-5), types.Float64), expression.NewLiteral(float64(10), types.Float64)}, nil, nil}, 175 {"Input base is valid string", []sql.Expression{expression.NewLiteral("4", types.LongText), expression.NewLiteral(float64(10), types.Float64)}, float64(1.6609640474436813), nil}, 176 {"Input base is invalid string", []sql.Expression{expression.NewLiteral("bbb", types.LongText), expression.NewLiteral(float64(10), types.Float64)}, nil, sql.ErrInvalidType}, 177 178 {"Input value is null", []sql.Expression{expression.NewLiteral(nil, types.Float64)}, nil, nil}, 179 {"Input value is zero", []sql.Expression{expression.NewLiteral(float64(0), types.Float64)}, nil, nil}, 180 {"Input value is negative", []sql.Expression{expression.NewLiteral(float64(-9), types.Float64)}, nil, nil}, 181 {"Input value is valid string", []sql.Expression{expression.NewLiteral("7", types.LongText)}, float64(1.9459101490553132), nil}, 182 {"Input value is invalid string", []sql.Expression{expression.NewLiteral("766j", types.LongText)}, nil, sql.ErrInvalidType}, 183 184 {"Input base is valid float64", []sql.Expression{expression.NewLiteral(float64(5), types.Float64), expression.NewLiteral(float64(99), types.Float64)}, float64(2.855108491376949), nil}, 185 {"Input base is valid float32", []sql.Expression{expression.NewLiteral(float32(6), types.Float32), expression.NewLiteral(float64(80), types.Float64)}, float64(2.4456556306420936), nil}, 186 {"Input base is valid int64", []sql.Expression{expression.NewLiteral(int64(8), types.Int64), expression.NewLiteral(float64(64), types.Float64)}, float64(2), nil}, 187 {"Input base is valid int32", []sql.Expression{expression.NewLiteral(int32(10), types.Int32), expression.NewLiteral(float64(100), types.Float64)}, float64(2), nil}, 188 189 {"Input value is valid float64", []sql.Expression{expression.NewLiteral(float64(5), types.Float64), expression.NewLiteral(float64(66), types.Float64)}, float64(2.6031788549643564), nil}, 190 {"Input value is valid float32", []sql.Expression{expression.NewLiteral(float32(3), types.Float32), expression.NewLiteral(float64(50), types.Float64)}, float64(3.560876795007312), nil}, 191 {"Input value is valid int64", []sql.Expression{expression.NewLiteral(int64(5), types.Int64), expression.NewLiteral(float64(77), types.Float64)}, float64(2.698958057527146), nil}, 192 {"Input value is valid int32", []sql.Expression{expression.NewLiteral(int32(4), types.Int32), expression.NewLiteral(float64(40), types.Float64)}, float64(2.6609640474436813), nil}, 193 } 194 195 for _, tt := range testCases { 196 f, _ := NewLog(tt.input...) 197 t.Run(tt.name, func(t *testing.T) { 198 t.Helper() 199 require := require.New(t) 200 result, err := f.Eval(sql.NewEmptyContext(), nil) 201 if tt.err != nil { 202 require.Error(err) 203 require.True(tt.err.Is(err)) 204 } else if tt.expected == nil { 205 require.NoError(err) 206 require.Nil(result) 207 } else { 208 require.NoError(err) 209 require.InEpsilonf(tt.expected, result, epsilon, fmt.Sprintf("Actual is: %v", result)) 210 } 211 }) 212 } 213 }