github.com/dolthub/go-mysql-server@v0.18.0/sql/types/enum_test.go (about)

     1  // Copyright 2022 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 types
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  	"strconv"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  	"github.com/stretchr/testify/require"
    26  
    27  	"github.com/dolthub/go-mysql-server/sql"
    28  )
    29  
    30  func TestEnumCompare(t *testing.T) {
    31  	tests := []struct {
    32  		vals        []string
    33  		collation   sql.CollationID
    34  		val1        interface{}
    35  		val2        interface{}
    36  		expectedCmp int
    37  	}{
    38  		{[]string{"one", "two"}, sql.Collation_Default, nil, 1, 1},
    39  		{[]string{"one", "two"}, sql.Collation_Default, "one", nil, -1},
    40  		{[]string{"one", "two"}, sql.Collation_Default, nil, nil, 0},
    41  		{[]string{"one", "two"}, sql.Collation_Default, 1, "two", -1},
    42  		{[]string{"one", "two"}, sql.Collation_Default, 2, []byte("one"), 1},
    43  		{[]string{"one", "two"}, sql.Collation_Default, "one", 1, 0},
    44  		{[]string{"one", "two"}, sql.Collation_Default, "one", "two", -1},
    45  		{[]string{"two", "one"}, sql.Collation_Default, "two", "one", -1},
    46  		{[]string{"0", "1", "2"}, sql.Collation_Default, 3, "2", 0},
    47  		{[]string{"0", "1", "2"}, sql.Collation_Default, 2, "1", 0},
    48  		{[]string{"0", "1", "2"}, sql.Collation_Default, "3", "2", 0},
    49  		{[]string{"one", "two"}, sql.Collation_Default, "ten", "twenty", 0},
    50  		{[]string{"one", "two"}, sql.Collation_Default, "one", "hundred", 1},
    51  		{[]string{"one", "two"}, sql.Collation_Default, "hundred", "one", -1},
    52  	}
    53  
    54  	for _, test := range tests {
    55  		t.Run(fmt.Sprintf("%v %v %v %v", test.vals, test.collation, test.val1, test.val2), func(t *testing.T) {
    56  			typ := MustCreateEnumType(test.vals, test.collation)
    57  			cmp, err := typ.Compare(test.val1, test.val2)
    58  			require.NoError(t, err)
    59  			assert.Equal(t, test.expectedCmp, cmp)
    60  		})
    61  	}
    62  }
    63  
    64  func TestEnumCreate(t *testing.T) {
    65  	tests := []struct {
    66  		vals               []string
    67  		collation          sql.CollationID
    68  		expectedValToIndex map[string]int
    69  		expectedErr        bool
    70  	}{
    71  		{[]string{"one"}, sql.Collation_Default, map[string]int{"one": 1}, false},
    72  		{[]string{" one ", "  two  "}, sql.Collation_Default,
    73  			map[string]int{" one": 1, "  two": 2}, false},
    74  		{[]string{"0", "1", "2"}, sql.Collation_Default,
    75  			map[string]int{"0": 1, "1": 2, "2": 3}, false},
    76  		{[]string{"one", "one "}, sql.Collation_binary,
    77  			map[string]int{"one": 1, "one ": 2}, false},
    78  		{[]string{}, sql.Collation_Default, nil, true},
    79  		{[]string{"one", "one"}, sql.Collation_Default, nil, true},
    80  		{[]string{"one", "one "}, sql.Collation_Default, nil, true},
    81  	}
    82  
    83  	for _, test := range tests {
    84  		t.Run(fmt.Sprintf("%v %v %v", test.vals, test.collation, test.expectedValToIndex), func(t *testing.T) {
    85  			typ, err := CreateEnumType(test.vals, test.collation)
    86  			if test.expectedErr {
    87  				assert.Error(t, err)
    88  			} else {
    89  				require.NoError(t, err)
    90  				assert.True(t, test.collation.Equals(typ.Collation()))
    91  				for val, i := range test.expectedValToIndex {
    92  					str, ok := typ.At(i)
    93  					if assert.True(t, ok) {
    94  						assert.Equal(t, val, str)
    95  					}
    96  					index := typ.IndexOf(val)
    97  					assert.Equal(t, i, index)
    98  				}
    99  			}
   100  		})
   101  	}
   102  }
   103  
   104  func TestEnumCreateTooLarge(t *testing.T) {
   105  	vals := make([]string, 65536)
   106  	for i := range vals {
   107  		vals[i] = strconv.Itoa(i)
   108  	}
   109  	_, err := CreateEnumType(vals, sql.Collation_Default)
   110  	require.Error(t, err)
   111  }
   112  
   113  func TestEnumConvert(t *testing.T) {
   114  	tests := []struct {
   115  		vals        []string
   116  		collation   sql.CollationID
   117  		val         interface{}
   118  		expectedVal interface{}
   119  		expectedErr bool
   120  	}{
   121  		{[]string{"one", "two"}, sql.Collation_Default, nil, nil, false},
   122  		{[]string{"one", "two"}, sql.Collation_Default, int(1), "one", false},
   123  		{[]string{"one", "two"}, sql.Collation_Default, int8(2), "two", false},
   124  		{[]string{"one", "two"}, sql.Collation_Default, int16(1), "one", false},
   125  		{[]string{"one", "two"}, sql.Collation_Default, int32(2), "two", false},
   126  		{[]string{"one", "two"}, sql.Collation_Default, int64(1), "one", false},
   127  		{[]string{"one", "two"}, sql.Collation_Default, uint(2), "two", false},
   128  		{[]string{"one", "two"}, sql.Collation_Default, uint8(1), "one", false},
   129  		{[]string{"one", "two"}, sql.Collation_Default, uint16(2), "two", false},
   130  		{[]string{"one", "two"}, sql.Collation_Default, uint32(1), "one", false},
   131  		{[]string{"one", "two"}, sql.Collation_Default, uint64(2), "two", false},
   132  		{[]string{"one", "two"}, sql.Collation_Default, "one", "one", false},
   133  		{[]string{"one", "two"}, sql.Collation_Default, []byte("two"), "two", false},
   134  		{[]string{"0", "1", "2"}, sql.Collation_Default, 3, "2", false},
   135  		{[]string{"0", "1", "2"}, sql.Collation_Default, 2, "1", false},
   136  		{[]string{"0", "1", "2"}, sql.Collation_Default, "3", "2", false},
   137  		{[]string{"0", "1", "2"}, sql.Collation_Default, "2", "2", false},
   138  
   139  		{[]string{"one", "two"}, sql.Collation_Default, 3, nil, true},
   140  		{[]string{"one", "two"}, sql.Collation_Default, 0, nil, true},
   141  		{[]string{"one", "two"}, sql.Collation_Default, "three", nil, true},
   142  		{[]string{"one", "two"}, sql.Collation_Default, time.Date(2019, 12, 12, 12, 12, 12, 0, time.UTC), nil, true},
   143  	}
   144  
   145  	for _, test := range tests {
   146  		t.Run(fmt.Sprintf("%v %v %v", test.vals, test.collation, test.val), func(t *testing.T) {
   147  			typ := MustCreateEnumType(test.vals, test.collation)
   148  			val, _, err := typ.Convert(test.val)
   149  			if test.expectedErr {
   150  				assert.Error(t, err)
   151  			} else {
   152  				require.NoError(t, err)
   153  				if test.val != nil {
   154  					umar, ok := typ.At(int(val.(uint16)))
   155  					require.True(t, ok)
   156  					cmp, err := typ.Compare(test.val, umar)
   157  					require.NoError(t, err)
   158  					assert.Equal(t, 0, cmp)
   159  					assert.Equal(t, typ.ValueType(), reflect.TypeOf(val))
   160  				} else {
   161  					assert.Equal(t, test.expectedVal, val)
   162  				}
   163  			}
   164  		})
   165  	}
   166  }
   167  
   168  func TestEnumString(t *testing.T) {
   169  	tests := []struct {
   170  		vals        []string
   171  		collation   sql.CollationID
   172  		expectedStr string
   173  	}{
   174  		{[]string{"one"}, sql.Collation_Default, "enum('one')"},
   175  		{[]string{"مرحبا", "こんにちは"}, sql.Collation_Default, "enum('مرحبا','こんにちは')"},
   176  		{[]string{" hi ", "  lo  "}, sql.Collation_Default, "enum(' hi','  lo')"},
   177  		{[]string{"a"}, sql.Collation_Default.CharacterSet().BinaryCollation(),
   178  			fmt.Sprintf("enum('a') COLLATE %v", sql.Collation_Default.CharacterSet().BinaryCollation())},
   179  	}
   180  
   181  	for _, test := range tests {
   182  		t.Run(fmt.Sprintf("%v %v", test.vals, test.collation), func(t *testing.T) {
   183  			typ := MustCreateEnumType(test.vals, test.collation)
   184  			assert.Equal(t, test.expectedStr, typ.String())
   185  		})
   186  	}
   187  }
   188  
   189  func TestEnumZero(t *testing.T) {
   190  	tests := []struct {
   191  		vals []string
   192  	}{
   193  		{[]string{"a"}},
   194  		{[]string{"a", "b"}},
   195  	}
   196  
   197  	for _, test := range tests {
   198  		t.Run(fmt.Sprintf("%v ok", test.vals), func(t *testing.T) {
   199  			typ := MustCreateEnumType(test.vals, sql.Collation_Default)
   200  			v, ok := typ.Zero().(uint16)
   201  			assert.True(t, ok)
   202  			assert.Equal(t, uint16(1), v)
   203  		})
   204  	}
   205  }