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  }