github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/schema/super_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  	"testing"
    19  
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  
    23  	"github.com/dolthub/dolt/go/libraries/doltcore/schema/typeinfo"
    24  	"github.com/dolthub/dolt/go/store/types"
    25  )
    26  
    27  var sch1 = mustSchema([]Column{
    28  	strCol("a", 1, true),
    29  	strCol("b", 2, false),
    30  	strCol("c", 3, false),
    31  })
    32  
    33  var sch2 = mustSchema([]Column{
    34  	strCol("aa", 1, true),
    35  	strCol("dd", 4, false),
    36  })
    37  
    38  var sch3 = mustSchema([]Column{
    39  	strCol("aaa", 1, true),
    40  	strCol("bbb", 2, false),
    41  	strCol("eee", 5, false),
    42  })
    43  
    44  var sch4 = mustSchema([]Column{
    45  	strCol("a", 1, true),
    46  	strCol("eeee", 5, false),
    47  	strCol("ffff", 6, false),
    48  })
    49  
    50  var nameCollisionWithSch1 = mustSchema([]Column{
    51  	strCol("a", 1, true),
    52  	strCol("b", 22, false),
    53  })
    54  
    55  var tagCollisionWithSch1 = mustSchema([]Column{
    56  	strCol("a", 1, true),
    57  	{"collision", 2, types.IntKind, false, typeinfo.Int32Type, "", false, "", nil},
    58  })
    59  
    60  type SuperSchemaTest struct {
    61  	// Name of the test
    62  	Name string
    63  	// Schemas to added to the SuperSchema
    64  	Schemas []Schema
    65  	// ExpectedSuperSchema to be created
    66  	ExpectedSuperSchema SuperSchema
    67  	// ExpectedGeneratedSchema generated by GenerateSchema()
    68  	ExpectedGeneratedSchema Schema
    69  	// Expected error message to be returned, if any
    70  	ExpectedErrString string
    71  }
    72  
    73  var SuperSchemaTests = []SuperSchemaTest{
    74  	{
    75  		Name:    "SuperSchema of one Schema",
    76  		Schemas: []Schema{sch1},
    77  		ExpectedSuperSchema: SuperSchema{
    78  			allCols: mustColColl([]Column{
    79  				strCol("", 1, true),
    80  				strCol("", 2, false),
    81  				strCol("", 3, false),
    82  			}),
    83  			tagNames: map[uint64][]string{1: {"a"}, 2: {"b"}, 3: {"c"}}},
    84  		ExpectedGeneratedSchema: sch1,
    85  	},
    86  	{
    87  		Name:    "SuperSchema of multiple Schemas",
    88  		Schemas: []Schema{sch1, sch2, sch3},
    89  		ExpectedSuperSchema: SuperSchema{
    90  			allCols: mustColColl([]Column{
    91  				strCol("", 1, true),
    92  				strCol("", 2, false),
    93  				strCol("", 3, false),
    94  				strCol("", 4, false),
    95  				strCol("", 5, false),
    96  			}),
    97  			tagNames: map[uint64][]string{1: {"aaa", "aa", "a"}, 2: {"bbb", "b"}, 3: {"c"}, 4: {"dd"}, 5: {"eee"}},
    98  		},
    99  		ExpectedGeneratedSchema: mustSchema([]Column{
   100  			strCol("aaa", 1, true),
   101  			strCol("bbb", 2, false),
   102  			strCol("c", 3, false),
   103  			strCol("dd", 4, false),
   104  			strCol("eee", 5, false),
   105  		}),
   106  	},
   107  	{
   108  		Name:    "SuperSchema respects order of added Schemas",
   109  		Schemas: []Schema{sch3, sch2, sch1},
   110  		ExpectedSuperSchema: SuperSchema{
   111  			allCols: mustColColl([]Column{
   112  				strCol("", 1, true),
   113  				strCol("", 2, false),
   114  				strCol("", 5, false),
   115  				strCol("", 4, false),
   116  				strCol("", 3, false),
   117  			}),
   118  			tagNames: map[uint64][]string{1: {"a", "aa", "aaa"}, 2: {"b", "bbb"}, 3: {"c"}, 4: {"dd"}, 5: {"eee"}},
   119  		},
   120  		ExpectedGeneratedSchema: mustSchema([]Column{
   121  			strCol("a", 1, true),
   122  			strCol("b", 2, false),
   123  			strCol("eee", 5, false),
   124  			strCol("dd", 4, false),
   125  			strCol("c", 3, false),
   126  		}),
   127  	},
   128  	{
   129  		Name:    "SuperSchema appends tag to disambiguate name collisions",
   130  		Schemas: []Schema{sch1, nameCollisionWithSch1},
   131  		ExpectedSuperSchema: SuperSchema{
   132  			allCols: mustColColl([]Column{
   133  				strCol("", 1, true),
   134  				strCol("", 2, false),
   135  				strCol("", 3, false),
   136  				strCol("", 22, false),
   137  			}),
   138  			tagNames: map[uint64][]string{1: {"a"}, 2: {"b"}, 3: {"c"}, 22: {"b"}},
   139  		},
   140  		ExpectedGeneratedSchema: mustSchema([]Column{
   141  			strCol("a", 1, true),
   142  			strCol("b_2", 2, false),
   143  			strCol("c", 3, false),
   144  			strCol("b_22", 22, false),
   145  		}),
   146  	},
   147  	{
   148  		Name:              "SuperSchema errors on tag collision",
   149  		Schemas:           []Schema{sch1, tagCollisionWithSch1},
   150  		ExpectedErrString: "tag collision for columns b and collision, different definitions (tag: 2)",
   151  	},
   152  }
   153  
   154  func TestSuperSchema(t *testing.T) {
   155  	for _, test := range SuperSchemaTests {
   156  		t.Run(test.Name, func(t *testing.T) {
   157  			testSuperSchema(t, test)
   158  		})
   159  	}
   160  	t.Run("SuperSchemaUnion", func(t *testing.T) {
   161  		testSuperSchemaUnion(t)
   162  	})
   163  }
   164  
   165  func testSuperSchema(t *testing.T, test SuperSchemaTest) {
   166  	ss, err := NewSuperSchema(test.Schemas...)
   167  	if test.ExpectedErrString != "" {
   168  		assert.Error(t, err, test.ExpectedErrString)
   169  	} else {
   170  		require.NoError(t, err)
   171  
   172  		assert.True(t, test.ExpectedSuperSchema.Equals(ss))
   173  		// ensure Equals() method works by comparing SuperSchema internals
   174  		superSchemaDeepEqual(t, &test.ExpectedSuperSchema, ss)
   175  
   176  		// ensure naming works correctly in GenerateSchema()
   177  		gs, err := ss.GenerateSchema()
   178  		require.NoError(t, err)
   179  		assert.Equal(t, test.ExpectedGeneratedSchema, gs)
   180  
   181  		eq := SchemasAreEqual(test.ExpectedGeneratedSchema, gs)
   182  		require.NoError(t, err)
   183  		assert.True(t, eq)
   184  	}
   185  }
   186  
   187  func testSuperSchemaUnion(t *testing.T) {
   188  	ss12, err := NewSuperSchema(sch1, sch2)
   189  	require.NoError(t, err)
   190  	ss34, err := NewSuperSchema(sch3, sch4)
   191  	require.NoError(t, err)
   192  
   193  	unionSuperSchema, err := SuperSchemaUnion(ss12, ss34)
   194  	require.NoError(t, err)
   195  	expectedGeneratedSchema := mustSchema([]Column{
   196  		strCol("a", 1, true),
   197  		strCol("bbb", 2, false),
   198  		strCol("c", 3, false),
   199  		strCol("dd", 4, false),
   200  		strCol("eeee", 5, false),
   201  		strCol("ffff", 6, false),
   202  	})
   203  	gs, err := unionSuperSchema.GenerateSchema()
   204  	require.NoError(t, err)
   205  	assert.Equal(t, expectedGeneratedSchema, gs)
   206  
   207  	// ensure that SuperSchemaUnion() respects order
   208  	unionSuperSchema, err = SuperSchemaUnion(ss34, ss12)
   209  	require.NoError(t, err)
   210  	expectedGeneratedSchema = mustSchema([]Column{
   211  		strCol("aa", 1, true),
   212  		strCol("b", 2, false),
   213  		strCol("eeee", 5, false),
   214  		strCol("ffff", 6, false),
   215  		strCol("c", 3, false),
   216  		strCol("dd", 4, false),
   217  	})
   218  	gs, err = unionSuperSchema.GenerateSchema()
   219  	require.NoError(t, err)
   220  	assert.Equal(t, expectedGeneratedSchema, gs)
   221  }
   222  
   223  func superSchemaDeepEqual(t *testing.T, ss1, ss2 *SuperSchema) {
   224  	assert.Equal(t, ss1.tagNames, ss2.tagNames)
   225  	assert.Equal(t, *ss1.allCols, *ss2.allCols)
   226  }
   227  
   228  func mustSchema(cols []Column) Schema {
   229  	return MustSchemaFromCols(mustColColl(cols))
   230  }
   231  
   232  func mustColColl(cols []Column) *ColCollection {
   233  	return NewColCollection(cols...)
   234  }
   235  
   236  func strCol(name string, tag uint64, isPK bool) Column {
   237  	return Column{name, tag, types.StringKind, isPK, typeinfo.StringDefaultType, "", false, "", nil}
   238  }