github.com/jbendotnet/noms@v0.0.0-20190904222105-c43e4293ea92/go/marshal/encode_type_test.go (about)

     1  // Copyright 2017 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  package marshal
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"reflect"
    11  	"testing"
    12  
    13  	"github.com/attic-labs/noms/go/nomdl"
    14  	"github.com/attic-labs/noms/go/types"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  func TestMarshalTypeType(tt *testing.T) {
    19  	t := func(exp *types.Type, ptr interface{}) {
    20  		p := reflect.ValueOf(ptr)
    21  		assert.NotEqual(tt, reflect.Ptr, p.Type().Kind())
    22  		actual, err := MarshalType(p.Interface())
    23  		assert.NoError(tt, err)
    24  		assert.NotNil(tt, actual, "%#v", p.Interface())
    25  		assert.True(tt, exp.Equals(actual))
    26  	}
    27  
    28  	t(types.NumberType, float32(0))
    29  	t(types.NumberType, float64(0))
    30  	t(types.NumberType, int(0))
    31  	t(types.NumberType, int16(0))
    32  	t(types.NumberType, int32(0))
    33  	t(types.NumberType, int64(0))
    34  	t(types.NumberType, int8(0))
    35  	t(types.NumberType, uint(0))
    36  	t(types.NumberType, uint16(0))
    37  	t(types.NumberType, uint32(0))
    38  	t(types.NumberType, uint64(0))
    39  	t(types.NumberType, uint8(0))
    40  
    41  	t(types.BoolType, true)
    42  	t(types.StringType, "hi")
    43  
    44  	var l []int
    45  	t(types.MakeListType(types.NumberType), l)
    46  
    47  	var m map[uint32]string
    48  	t(types.MakeMapType(types.NumberType, types.StringType), m)
    49  
    50  	t(types.MakeListType(types.ValueType), types.List{})
    51  	t(types.MakeSetType(types.ValueType), types.Set{})
    52  	t(types.MakeMapType(types.ValueType, types.ValueType), types.Map{})
    53  	t(types.MakeRefType(types.ValueType), types.Ref{})
    54  
    55  	type TestStruct struct {
    56  		Str string
    57  		Num float64
    58  	}
    59  	var str TestStruct
    60  	t(types.MakeStructTypeFromFields("TestStruct", types.FieldMap{
    61  		"str": types.StringType,
    62  		"num": types.NumberType,
    63  	}), str)
    64  
    65  	// Same again to test caching
    66  	t(types.MakeStructTypeFromFields("TestStruct", types.FieldMap{
    67  		"str": types.StringType,
    68  		"num": types.NumberType,
    69  	}), str)
    70  
    71  	anonStruct := struct {
    72  		B bool
    73  	}{
    74  		true,
    75  	}
    76  	t(types.MakeStructTypeFromFields("", types.FieldMap{
    77  		"b": types.BoolType,
    78  	}), anonStruct)
    79  
    80  	type TestNestedStruct struct {
    81  		A []int16
    82  		B TestStruct
    83  		C float64
    84  	}
    85  	var nestedStruct TestNestedStruct
    86  	t(types.MakeStructTypeFromFields("TestNestedStruct", types.FieldMap{
    87  		"a": types.MakeListType(types.NumberType),
    88  		"b": types.MakeStructTypeFromFields("TestStruct", types.FieldMap{
    89  			"str": types.StringType,
    90  			"num": types.NumberType,
    91  		}),
    92  		"c": types.NumberType,
    93  	}), nestedStruct)
    94  
    95  	type testStruct struct {
    96  		Str string
    97  		Num float64
    98  	}
    99  	var ts testStruct
   100  	t(types.MakeStructTypeFromFields("TestStruct", types.FieldMap{
   101  		"str": types.StringType,
   102  		"num": types.NumberType,
   103  	}), ts)
   104  }
   105  
   106  //
   107  func assertMarshalTypeErrorMessage(t *testing.T, v interface{}, expectedMessage string) {
   108  	_, err := MarshalType(v)
   109  	assert.Error(t, err)
   110  	assert.Equal(t, expectedMessage, err.Error())
   111  }
   112  
   113  func TestMarshalTypeInvalidTypes(t *testing.T) {
   114  	assertMarshalTypeErrorMessage(t, make(chan int), "Type is not supported, type: chan int")
   115  }
   116  
   117  func TestMarshalTypeEmbeddedStruct(t *testing.T) {
   118  	assert := assert.New(t)
   119  
   120  	type EmbeddedStruct struct {
   121  		B bool
   122  	}
   123  	type TestStruct struct {
   124  		EmbeddedStruct
   125  		A int
   126  	}
   127  
   128  	var s TestStruct
   129  	typ := MustMarshalType(s)
   130  
   131  	assert.True(types.MakeStructTypeFromFields("TestStruct", types.FieldMap{
   132  		"a": types.NumberType,
   133  		"b": types.BoolType,
   134  	}).Equals(typ))
   135  }
   136  
   137  func TestMarshalTypeEmbeddedStructSkip(t *testing.T) {
   138  	assert := assert.New(t)
   139  
   140  	type EmbeddedStruct struct {
   141  		B bool
   142  	}
   143  	type TestStruct struct {
   144  		EmbeddedStruct `noms:"-"`
   145  		A              int
   146  	}
   147  
   148  	var s TestStruct
   149  	typ := MustMarshalType(s)
   150  
   151  	assert.True(types.MakeStructTypeFromFields("TestStruct", types.FieldMap{
   152  		"a": types.NumberType,
   153  	}).Equals(typ))
   154  }
   155  
   156  func TestMarshalTypeEmbeddedStructNamed(t *testing.T) {
   157  	assert := assert.New(t)
   158  
   159  	type EmbeddedStruct struct {
   160  		B bool
   161  	}
   162  	type TestStruct struct {
   163  		EmbeddedStruct `noms:"em"`
   164  		A              int
   165  	}
   166  
   167  	var s TestStruct
   168  	typ := MustMarshalType(s)
   169  
   170  	assert.True(types.MakeStructTypeFromFields("TestStruct", types.FieldMap{
   171  		"a": types.NumberType,
   172  		"em": types.MakeStructTypeFromFields("EmbeddedStruct", types.FieldMap{
   173  			"b": types.BoolType,
   174  		}),
   175  	}).Equals(typ))
   176  }
   177  
   178  func TestMarshalTypeEncodeNonExportedField(t *testing.T) {
   179  	type TestStruct struct {
   180  		x int
   181  	}
   182  	assertMarshalTypeErrorMessage(t, TestStruct{1}, "Non exported fields are not supported, type: marshal.TestStruct")
   183  }
   184  
   185  func TestMarshalTypeEncodeTaggingSkip(t *testing.T) {
   186  	assert := assert.New(t)
   187  
   188  	type S struct {
   189  		Abc int `noms:"-"`
   190  		Def bool
   191  	}
   192  	var s S
   193  	typ, err := MarshalType(s)
   194  	assert.NoError(err)
   195  	assert.True(types.MakeStructTypeFromFields("S", types.FieldMap{
   196  		"def": types.BoolType,
   197  	}).Equals(typ))
   198  }
   199  
   200  func TestMarshalTypeNamedFields(t *testing.T) {
   201  	assert := assert.New(t)
   202  
   203  	type S struct {
   204  		Aaa int  `noms:"a"`
   205  		Bbb bool `noms:"B"`
   206  		Ccc string
   207  	}
   208  	var s S
   209  	typ, err := MarshalType(s)
   210  	assert.NoError(err)
   211  	assert.True(types.MakeStructTypeFromFields("S", types.FieldMap{
   212  		"a":   types.NumberType,
   213  		"B":   types.BoolType,
   214  		"ccc": types.StringType,
   215  	}).Equals(typ))
   216  }
   217  
   218  func TestMarshalTypeInvalidNamedFields(t *testing.T) {
   219  	type S struct {
   220  		A int `noms:"1a"`
   221  	}
   222  	var s S
   223  	assertMarshalTypeErrorMessage(t, s, "Invalid struct field name: 1a")
   224  }
   225  
   226  func TestMarshalTypeOmitEmpty(t *testing.T) {
   227  	assert := assert.New(t)
   228  
   229  	type S struct {
   230  		String string `noms:",omitempty"`
   231  	}
   232  	var s S
   233  	typ, err := MarshalType(s)
   234  	assert.NoError(err)
   235  	assert.True(types.MakeStructType("S", types.StructField{Name: "string", Type: types.StringType, Optional: true}).Equals(typ))
   236  }
   237  
   238  func ExampleMarshalType() {
   239  
   240  	type Person struct {
   241  		Given  string
   242  		Female bool
   243  	}
   244  	var person Person
   245  	personNomsType, err := MarshalType(person)
   246  	if err != nil {
   247  		fmt.Println(err)
   248  		return
   249  	}
   250  
   251  	fmt.Println(personNomsType.Describe())
   252  	// Output: Struct Person {
   253  	//   female: Bool,
   254  	//   given: String,
   255  	// }
   256  }
   257  
   258  func TestMarshalTypeSlice(t *testing.T) {
   259  	assert := assert.New(t)
   260  
   261  	s := []string{"a", "b", "c"}
   262  	typ, err := MarshalType(s)
   263  	assert.NoError(err)
   264  	assert.True(types.MakeListType(types.StringType).Equals(typ))
   265  }
   266  
   267  func TestMarshalTypeArray(t *testing.T) {
   268  	assert := assert.New(t)
   269  
   270  	a := [3]int{1, 2, 3}
   271  	typ, err := MarshalType(a)
   272  	assert.NoError(err)
   273  	assert.True(types.MakeListType(types.NumberType).Equals(typ))
   274  }
   275  
   276  func TestMarshalTypeStructWithSlice(t *testing.T) {
   277  	assert := assert.New(t)
   278  
   279  	type S struct {
   280  		List []int
   281  	}
   282  	var s S
   283  	typ, err := MarshalType(s)
   284  	assert.NoError(err)
   285  	assert.True(types.MakeStructTypeFromFields("S", types.FieldMap{
   286  		"list": types.MakeListType(types.NumberType),
   287  	}).Equals(typ))
   288  }
   289  
   290  func TestMarshalTypeRecursive(t *testing.T) {
   291  	assert := assert.New(t)
   292  
   293  	type Node struct {
   294  		Value    int
   295  		Children []Node
   296  	}
   297  	var n Node
   298  	typ, err := MarshalType(n)
   299  	assert.NoError(err)
   300  
   301  	typ2 := types.MakeStructType("Node",
   302  		types.StructField{
   303  			Name: "children",
   304  			Type: types.MakeListType(types.MakeCycleType("Node")),
   305  		},
   306  		types.StructField{
   307  			Name: "value",
   308  			Type: types.NumberType,
   309  		},
   310  	)
   311  	assert.True(typ2.Equals(typ))
   312  }
   313  
   314  func TestMarshalTypeMap(t *testing.T) {
   315  	assert := assert.New(t)
   316  
   317  	var m map[string]int
   318  	typ, err := MarshalType(m)
   319  	assert.NoError(err)
   320  	assert.True(types.MakeMapType(types.StringType, types.NumberType).Equals(typ))
   321  
   322  	type S struct {
   323  		N string
   324  	}
   325  
   326  	var m2 map[S]bool
   327  	typ, err = MarshalType(m2)
   328  	assert.NoError(err)
   329  	assert.True(types.MakeMapType(
   330  		types.MakeStructTypeFromFields("S", types.FieldMap{
   331  			"n": types.StringType,
   332  		}),
   333  		types.BoolType).Equals(typ))
   334  }
   335  
   336  func TestMarshalTypeSet(t *testing.T) {
   337  	assert := assert.New(t)
   338  
   339  	type S struct {
   340  		A map[int]struct{} `noms:",set"`
   341  		B map[int]struct{}
   342  		C map[int]string      `noms:",set"`
   343  		D map[string]struct{} `noms:",set"`
   344  		E map[string]struct{}
   345  		F map[string]int `noms:",set"`
   346  		G []int          `noms:",set"`
   347  		H string         `noms:",set"`
   348  	}
   349  	var s S
   350  	typ, err := MarshalType(s)
   351  	assert.NoError(err)
   352  
   353  	emptyStructType := types.MakeStructTypeFromFields("", types.FieldMap{})
   354  
   355  	assert.True(types.MakeStructTypeFromFields("S", types.FieldMap{
   356  		"a": types.MakeSetType(types.NumberType),
   357  		"b": types.MakeMapType(types.NumberType, emptyStructType),
   358  		"c": types.MakeMapType(types.NumberType, types.StringType),
   359  		"d": types.MakeSetType(types.StringType),
   360  		"e": types.MakeMapType(types.StringType, emptyStructType),
   361  		"f": types.MakeMapType(types.StringType, types.NumberType),
   362  		"g": types.MakeSetType(types.NumberType),
   363  		"h": types.StringType,
   364  	}).Equals(typ))
   365  }
   366  
   367  func TestEncodeTypeOpt(t *testing.T) {
   368  	assert := assert.New(t)
   369  
   370  	tc := []struct {
   371  		in       interface{}
   372  		opt      Opt
   373  		wantType *types.Type
   374  	}{
   375  		{
   376  			[]string{},
   377  			Opt{},
   378  			types.MakeListType(types.StringType),
   379  		},
   380  		{
   381  			[]string{},
   382  			Opt{Set: true},
   383  			types.MakeSetType(types.StringType),
   384  		},
   385  		{
   386  			map[string]struct{}{},
   387  			Opt{},
   388  			types.MakeMapType(types.StringType, types.MakeStructType("")),
   389  		},
   390  		{
   391  			map[string]struct{}{},
   392  			Opt{Set: true},
   393  			types.MakeSetType(types.StringType),
   394  		},
   395  	}
   396  
   397  	for _, t := range tc {
   398  		r, err := MarshalTypeOpt(t.in, t.opt)
   399  		assert.True(t.wantType.Equals(r))
   400  		assert.Nil(err)
   401  	}
   402  }
   403  
   404  func TestMarshalTypeSetWithTags(t *testing.T) {
   405  	assert := assert.New(t)
   406  
   407  	type S struct {
   408  		A map[int]struct{} `noms:"foo,set"`
   409  		B map[int]struct{} `noms:",omitempty,set"`
   410  		C map[int]struct{} `noms:"bar,omitempty,set"`
   411  	}
   412  
   413  	var s S
   414  	typ, err := MarshalType(s)
   415  	assert.NoError(err)
   416  	assert.True(types.MakeStructType("S",
   417  		types.StructField{Name: "foo", Type: types.MakeSetType(types.NumberType), Optional: false},
   418  		types.StructField{Name: "b", Type: types.MakeSetType(types.NumberType), Optional: true},
   419  		types.StructField{Name: "bar", Type: types.MakeSetType(types.NumberType), Optional: true},
   420  	).Equals(typ))
   421  }
   422  
   423  func TestMarshalTypeInvalidTag(t *testing.T) {
   424  
   425  	type S struct {
   426  		F string `noms:",omitEmpty"`
   427  	}
   428  	var s S
   429  	_, err := MarshalType(s)
   430  	assert.Error(t, err)
   431  	assert.Equal(t, `Unrecognized tag: omitEmpty`, err.Error())
   432  }
   433  
   434  func TestMarshalTypeCanSkipUnexportedField(t *testing.T) {
   435  	assert := assert.New(t)
   436  
   437  	type S struct {
   438  		Abc         int
   439  		notExported bool `noms:"-"`
   440  	}
   441  	var s S
   442  	typ, err := MarshalType(s)
   443  	assert.NoError(err)
   444  	assert.True(types.MakeStructTypeFromFields("S", types.FieldMap{
   445  		"abc": types.NumberType,
   446  	}).Equals(typ))
   447  }
   448  
   449  func TestMarshalTypeOriginal(t *testing.T) {
   450  	assert := assert.New(t)
   451  
   452  	type S struct {
   453  		Foo int          `noms:",omitempty"`
   454  		Bar types.Struct `noms:",original"`
   455  	}
   456  
   457  	var s S
   458  	typ, err := MarshalType(s)
   459  	assert.NoError(err)
   460  	assert.True(types.MakeStructType("S",
   461  		types.StructField{Name: "foo", Type: types.NumberType, Optional: true},
   462  	).Equals(typ))
   463  }
   464  
   465  func TestMarshalTypeNomsTypes(t *testing.T) {
   466  	assert := assert.New(t)
   467  
   468  	type S struct {
   469  		Blob   types.Blob
   470  		Bool   types.Bool
   471  		Number types.Number
   472  		String types.String
   473  		Type   *types.Type
   474  	}
   475  	var s S
   476  	assert.True(MustMarshalType(s).Equals(
   477  		types.MakeStructTypeFromFields("S", types.FieldMap{
   478  			"blob":   types.BlobType,
   479  			"bool":   types.BoolType,
   480  			"number": types.NumberType,
   481  			"string": types.StringType,
   482  			"type":   types.TypeType,
   483  		}),
   484  	))
   485  }
   486  
   487  func (t primitiveType) MarshalNomsType() (*types.Type, error) {
   488  	return types.NumberType, nil
   489  }
   490  
   491  func TestTypeMarshalerPrimitiveType(t *testing.T) {
   492  	assert := assert.New(t)
   493  
   494  	var u primitiveType
   495  	typ := MustMarshalType(u)
   496  	assert.Equal(types.NumberType, typ)
   497  }
   498  
   499  func (u primitiveSliceType) MarshalNomsType() (*types.Type, error) {
   500  	return types.StringType, nil
   501  }
   502  
   503  func TestTypeMarshalerPrimitiveSliceType(t *testing.T) {
   504  	assert := assert.New(t)
   505  
   506  	var u primitiveSliceType
   507  	typ := MustMarshalType(u)
   508  	assert.Equal(types.StringType, typ)
   509  }
   510  
   511  func (u primitiveMapType) MarshalNomsType() (*types.Type, error) {
   512  	return types.MakeSetType(types.StringType), nil
   513  }
   514  
   515  func TestTypeMarshalerPrimitiveMapType(t *testing.T) {
   516  	assert := assert.New(t)
   517  
   518  	var u primitiveMapType
   519  	typ := MustMarshalType(u)
   520  	assert.Equal(types.MakeSetType(types.StringType), typ)
   521  }
   522  
   523  func TestTypeMarshalerPrimitiveStructTypeNoMarshalNomsType(t *testing.T) {
   524  	assert := assert.New(t)
   525  
   526  	var u primitiveStructType
   527  	_, err := MarshalType(u)
   528  	assert.Error(err)
   529  	assert.Equal("Cannot marshal type which implements marshal.Marshaler, perhaps implement marshal.TypeMarshaler for marshal.primitiveStructType", err.Error())
   530  }
   531  
   532  func (u builtinType) MarshalNomsType() (*types.Type, error) {
   533  	return types.StringType, nil
   534  }
   535  
   536  func TestTypeMarshalerBuiltinType(t *testing.T) {
   537  	assert := assert.New(t)
   538  
   539  	var u builtinType
   540  	typ := MustMarshalType(u)
   541  	assert.Equal(types.StringType, typ)
   542  }
   543  
   544  func (u wrappedMarshalerType) MarshalNomsType() (*types.Type, error) {
   545  	return types.NumberType, nil
   546  }
   547  
   548  func TestTypeMarshalerWrapperMarshalerType(t *testing.T) {
   549  	assert := assert.New(t)
   550  
   551  	var u wrappedMarshalerType
   552  	typ := MustMarshalType(u)
   553  	assert.Equal(types.NumberType, typ)
   554  }
   555  
   556  func (u returnsMarshalerError) MarshalNomsType() (*types.Type, error) {
   557  	return nil, errors.New("expected error")
   558  }
   559  
   560  func (u returnsMarshalerNil) MarshalNomsType() (*types.Type, error) {
   561  	return nil, nil
   562  }
   563  
   564  func (u panicsMarshaler) MarshalNomsType() (*types.Type, error) {
   565  	panic("panic")
   566  }
   567  
   568  func TestTypeMarshalerErrors(t *testing.T) {
   569  	assert := assert.New(t)
   570  
   571  	expErr := errors.New("expected error")
   572  	var m1 returnsMarshalerError
   573  	_, actErr := MarshalType(m1)
   574  	assert.Equal(expErr, actErr)
   575  
   576  	var m2 returnsMarshalerNil
   577  	assert.Panics(func() { MarshalType(m2) })
   578  
   579  	var m3 panicsMarshaler
   580  	assert.Panics(func() { MarshalType(m3) })
   581  }
   582  
   583  func TestMarshalTypeStructName(t *testing.T) {
   584  	assert := assert.New(t)
   585  
   586  	var ts TestStructWithNameImpl
   587  	typ := MustMarshalType(ts)
   588  	assert.True(types.MakeStructType("A", types.StructField{Name: "x", Type: types.NumberType, Optional: false}).Equals(typ), typ.Describe())
   589  }
   590  
   591  func TestMarshalTypeStructName2(t *testing.T) {
   592  	assert := assert.New(t)
   593  
   594  	var ts TestStructWithNameImpl2
   595  	typ := MustMarshalType(ts)
   596  	assert.True(types.MakeStructType("", types.StructField{Name: "x", Type: types.NumberType, Optional: false}).Equals(typ), typ.Describe())
   597  }
   598  
   599  type OutPhoto struct {
   600  	Faces             []OutFace `noms:",set"`
   601  	SomeOtherFacesSet []OutFace `noms:",set"`
   602  }
   603  
   604  type OutFace struct {
   605  	Blob types.Ref
   606  }
   607  
   608  func (f OutFace) MarshalNomsStructName() string {
   609  	return "Face"
   610  }
   611  
   612  func TestMarshalTypeOutface(t *testing.T) {
   613  
   614  	typ := MustMarshalType(OutPhoto{})
   615  	expectedType := nomdl.MustParseType(`Struct OutPhoto {
   616            faces: Set<Struct Face {
   617              blob: Ref<Value>,
   618            }>,
   619            someOtherFacesSet: Set<Cycle<Face>>,
   620          }`)
   621  	assert.True(t, typ.Equals(expectedType))
   622  }