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  }