github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/schema/schema_test.go (about) 1 // Copyright 2019 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 schema 16 17 import ( 18 "reflect" 19 "strings" 20 "testing" 21 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 25 "github.com/dolthub/dolt/go/libraries/doltcore/schema/typeinfo" 26 "github.com/dolthub/dolt/go/store/types" 27 ) 28 29 const ( 30 lnColName = "last" 31 fnColName = "first" 32 addrColName = "address" 33 ageColName = "age" 34 titleColName = "title" 35 reservedColName = "reserved" 36 lnColTag = 1 37 fnColTag = 0 38 addrColTag = 6 39 ageColTag = 4 40 titleColTag = 40 41 reservedColTag = 50 42 ) 43 44 var lnVal = types.String("astley") 45 var fnVal = types.String("rick") 46 var addrVal = types.String("123 Fake St") 47 var ageVal = types.Uint(53) 48 var titleVal = types.NullValue 49 50 var pkCols = []Column{ 51 {lnColName, lnColTag, types.StringKind, true, typeinfo.StringDefaultType, "", false, "", nil}, 52 {fnColName, fnColTag, types.StringKind, true, typeinfo.StringDefaultType, "", false, "", nil}, 53 } 54 var nonPkCols = []Column{ 55 {addrColName, addrColTag, types.StringKind, false, typeinfo.StringDefaultType, "", false, "", nil}, 56 {ageColName, ageColTag, types.UintKind, false, typeinfo.FromKind(types.UintKind), "", false, "", nil}, 57 {titleColName, titleColTag, types.StringKind, false, typeinfo.StringDefaultType, "", false, "", nil}, 58 {reservedColName, reservedColTag, types.StringKind, false, typeinfo.StringDefaultType, "", false, "", nil}, 59 } 60 61 var allCols = append(append([]Column(nil), pkCols...), nonPkCols...) 62 63 func TestSchema(t *testing.T) { 64 colColl := NewColCollection(allCols...) 65 schFromCols, err := SchemaFromCols(colColl) 66 require.NoError(t, err) 67 68 testSchema("SchemaFromCols", schFromCols, t) 69 70 testKeyColColl := NewColCollection(pkCols...) 71 testNonKeyColsColl := NewColCollection(nonPkCols...) 72 schFromPKAndNonPKCols, _ := SchemaFromPKAndNonPKCols(testKeyColColl, testNonKeyColsColl) 73 74 testSchema("SchemaFromPKAndNonPKCols", schFromPKAndNonPKCols, t) 75 76 eq := SchemasAreEqual(schFromCols, schFromPKAndNonPKCols) 77 assert.True(t, eq, "schemas should be equal") 78 } 79 80 func TestSchemaWithNoPKs(t *testing.T) { 81 colColl := NewColCollection(nonPkCols...) 82 _, _ = SchemaFromCols(colColl) 83 84 assert.NotPanics(t, func() { 85 UnkeyedSchemaFromCols(colColl) 86 }) 87 } 88 89 func TestSchemaOverlap(t *testing.T) { 90 colColl := NewColCollection(nonPkCols...) 91 sch, _ := SchemaFromCols(colColl) 92 93 names := []string{addrColName, ageColName} 94 kinds := []types.NomsKind{types.StringKind, types.UintKind} 95 res := GetSharedCols(sch, names, kinds) 96 97 cmp := map[string]uint64{ 98 addrColName: addrColTag, 99 ageColName: ageColTag, 100 } 101 102 assert.Equal(t, res, cmp) 103 } 104 105 func TestIsKeyless(t *testing.T) { 106 cc := NewColCollection(allCols...) 107 pkSch, err := SchemaFromCols(cc) 108 require.NoError(t, err) 109 110 ok := IsKeyless(pkSch) 111 assert.False(t, ok) 112 113 cc = NewColCollection(nonPkCols...) 114 115 keylessSch, err := SchemaFromCols(cc) 116 assert.NoError(t, err) 117 118 ok = IsKeyless(keylessSch) 119 assert.True(t, ok) 120 } 121 122 func TestValidateForInsert(t *testing.T) { 123 t.Run("Validate good", func(t *testing.T) { 124 colColl := NewColCollection(allCols...) 125 assert.NoError(t, ValidateForInsert(colColl)) 126 }) 127 128 t.Run("Name collision", func(t *testing.T) { 129 cols := append(allCols, Column{titleColName, 100, types.StringKind, false, typeinfo.StringDefaultType, "", false, "", nil}) 130 colColl := NewColCollection(cols...) 131 132 err := ValidateForInsert(colColl) 133 assert.Error(t, err) 134 assert.Equal(t, err, ErrColNameCollision) 135 }) 136 137 t.Run("Case insensitive collision", func(t *testing.T) { 138 cols := append(allCols, Column{strings.ToUpper(titleColName), 100, types.StringKind, false, typeinfo.StringDefaultType, "", false, "", nil}) 139 colColl := NewColCollection(cols...) 140 141 err := ValidateForInsert(colColl) 142 assert.Error(t, err) 143 assert.Equal(t, err, ErrColNameCollision) 144 }) 145 146 t.Run("Tag collision", func(t *testing.T) { 147 cols := append(allCols, Column{"newCol", lnColTag, types.StringKind, false, typeinfo.StringDefaultType, "", false, "", nil}) 148 colColl := NewColCollection(cols...) 149 150 err := ValidateForInsert(colColl) 151 assert.Error(t, err) 152 assert.Equal(t, err, ErrColTagCollision) 153 }) 154 } 155 156 func testSchema(method string, sch Schema, t *testing.T) { 157 validateCols(t, allCols, sch.GetAllCols(), method+"GetAllCols") 158 validateCols(t, pkCols, sch.GetPKCols(), method+"GetPKCols") 159 validateCols(t, nonPkCols, sch.GetNonPKCols(), method+"GetNonPKCols") 160 161 extracted, err := ExtractAllColNames(sch) 162 assert.NoError(t, err) 163 164 expExt := map[uint64]string{ 165 lnColTag: lnColName, 166 fnColTag: fnColName, 167 ageColTag: ageColName, 168 addrColTag: addrColName, 169 titleColTag: titleColName, 170 reservedColTag: reservedColName, 171 } 172 173 if !reflect.DeepEqual(extracted, expExt) { 174 t.Error("extracted columns did not match expectation") 175 } 176 177 if col, ok := ColFromName(sch, titleColName); !ok { 178 t.Error("Failed to get by name") 179 } else if col.Tag != titleColTag { 180 t.Error("Unexpected tag") 181 } 182 183 if col, ok := ColFromTag(sch, titleColTag); !ok { 184 t.Error("Failed to get by name") 185 } else if col.Name != titleColName { 186 t.Error("Unexpected tag") 187 } 188 } 189 190 func validateCols(t *testing.T, cols []Column, colColl *ColCollection, msg string) { 191 if !reflect.DeepEqual(cols, colColl.cols) { 192 t.Error() 193 } 194 }