mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-18 22:40:35 +00:00
refactor(validation-gen): streamline type validation logic
- Consolidated type validation checks into a new function for improved readability and maintainability. - Updated the method to utilize the new validation function, simplifying error handling for unsupported types. - Removed redundant code related to pointer and map validations, enhancing clarity in the validation process. - Adjusted test cases in to reflect changes in type handling and ensure consistency with the new validation logic. Co-authored-by: Tim Hockin <thockin@google.com> Co-authored-by: Aaron Prindle <aprindle@google.com> Co-authored-by: Joe Betz <jpbetz@google.com>
This commit is contained in:
@@ -66,7 +66,8 @@ func IsNilableType(t *types.Type) bool {
|
||||
// - given `type X []int; *X`, returns `*[]int`
|
||||
func NativeType(t *types.Type) *types.Type {
|
||||
ptrs := 0
|
||||
for {
|
||||
conditionMet := false
|
||||
for !conditionMet {
|
||||
switch t.Kind {
|
||||
case types.Alias:
|
||||
t = t.Underlying
|
||||
@@ -74,10 +75,9 @@ func NativeType(t *types.Type) *types.Type {
|
||||
ptrs++
|
||||
t = t.Elem
|
||||
default:
|
||||
goto done
|
||||
conditionMet = true
|
||||
}
|
||||
}
|
||||
done:
|
||||
for range ptrs {
|
||||
t = types.PointerTo(t)
|
||||
}
|
||||
|
||||
@@ -237,56 +237,10 @@ func (td *typeDiscoverer) discoverType(t *types.Type, fldPath *field.Path) (*typ
|
||||
}
|
||||
}
|
||||
|
||||
// Catch some edge cases that we don't want to handle (yet?). This happens
|
||||
// Catch some cases that we don't want to handle (yet?). This happens
|
||||
// as early as possible to make all the other code simpler.
|
||||
switch t.Kind {
|
||||
case types.Builtin, types.Struct:
|
||||
// Allowed
|
||||
case types.Interface:
|
||||
// We can't do much with interfaces, but they pop up in some places
|
||||
// like RawExtension.
|
||||
case types.Alias:
|
||||
if t.Underlying.Kind == types.Pointer {
|
||||
return nil, fmt.Errorf("field %s (%s): typedefs to pointers are not supported", fldPath.String(), t)
|
||||
}
|
||||
case types.Pointer:
|
||||
pointee := util.NativeType(t.Elem)
|
||||
switch pointee.Kind {
|
||||
case types.Pointer:
|
||||
return nil, fmt.Errorf("field %s (%s): pointers to pointers are not supported", fldPath.String(), t)
|
||||
case types.Slice, types.Array:
|
||||
return nil, fmt.Errorf("field %s (%s): pointers to lists are not supported", fldPath.String(), t)
|
||||
case types.Map:
|
||||
return nil, fmt.Errorf("field %s (%s): pointers to maps are not supported", fldPath.String(), t)
|
||||
}
|
||||
case types.Array:
|
||||
return nil, fmt.Errorf("field %s (%s): fixed-size arrays are not supported", fldPath.String(), t)
|
||||
case types.Slice:
|
||||
elem := util.NativeType(t.Elem)
|
||||
switch elem.Kind {
|
||||
case types.Pointer:
|
||||
return nil, fmt.Errorf("field %s (%s): lists of pointers are not supported", fldPath.String(), t)
|
||||
case types.Slice:
|
||||
if util.NativeType(elem.Elem) != types.Byte {
|
||||
return nil, fmt.Errorf("field %s (%s): lists of lists are not supported", fldPath.String(), t)
|
||||
}
|
||||
case types.Map:
|
||||
return nil, fmt.Errorf("field %s (%s): lists of maps are not supported", fldPath.String(), t)
|
||||
}
|
||||
case types.Map:
|
||||
key := util.NativeType(t.Key)
|
||||
if key != types.String {
|
||||
return nil, fmt.Errorf("field %s (%s): maps with non-string keys are not supported", fldPath.String(), t)
|
||||
}
|
||||
elem := util.NativeType(t.Elem)
|
||||
switch elem.Kind {
|
||||
case types.Pointer:
|
||||
return nil, fmt.Errorf("field %s (%s): maps of pointers are not supported", fldPath.String(), t)
|
||||
case types.Map:
|
||||
return nil, fmt.Errorf("field %s (%s): maps of maps are not supported", fldPath.String(), t)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("field %s (%v, kind %v) is not supported", fldPath.String(), t, t.Kind)
|
||||
if err := td.verifySupportedType(t); err != nil {
|
||||
return nil, fmt.Errorf("field %s (%s): %w", fldPath.String(), t, err)
|
||||
}
|
||||
|
||||
// Discovery applies to values, not pointers.
|
||||
@@ -410,11 +364,7 @@ func (td *typeDiscoverer) discoverType(t *types.Type, fldPath *field.Path) (*typ
|
||||
} else if validations.Empty() {
|
||||
klog.V(6).InfoS("no type-attached validations", "type", t)
|
||||
} else {
|
||||
// TODO: This check is placed here to allow map-of-slices fields to exist in the type
|
||||
// system, while preventing validation on them since that functionality is not yet
|
||||
// implemented. Once validation support for map-of-slices is added, this check should
|
||||
// be removed.
|
||||
if util.NativeType(t).Kind == types.Map && util.NativeType(t).Elem.Kind == types.Slice {
|
||||
if util.NonPointer(util.NativeType(t)).Kind == types.Map && util.NonPointer(util.NativeType(t)).Elem.Kind == types.Slice {
|
||||
return nil, fmt.Errorf("field %s: validation for map of slices is not supported", fldPath)
|
||||
}
|
||||
klog.V(5).InfoS("found type-attached validations", "n", validations.Len(), "type", t)
|
||||
@@ -532,6 +482,61 @@ func (td *typeDiscoverer) discoverType(t *types.Type, fldPath *field.Path) (*typ
|
||||
return thisNode, nil
|
||||
}
|
||||
|
||||
// verifySupportedType checks whether the given type is supported.
|
||||
func (td *typeDiscoverer) verifySupportedType(t *types.Type) error {
|
||||
switch t.Kind {
|
||||
case types.Builtin, types.Struct:
|
||||
// Allowed
|
||||
case types.Interface:
|
||||
// We can't do much with interfaces, but they pop up in some places
|
||||
// like RawExtension.
|
||||
case types.Alias:
|
||||
if t.Underlying.Kind == types.Pointer {
|
||||
return fmt.Errorf("typedefs to pointers are not supported")
|
||||
}
|
||||
case types.Pointer:
|
||||
pointee := util.NativeType(t.Elem)
|
||||
switch pointee.Kind {
|
||||
case types.Pointer:
|
||||
return fmt.Errorf("pointers to pointers are not supported")
|
||||
case types.Slice, types.Array:
|
||||
return fmt.Errorf("pointers to lists are not supported")
|
||||
case types.Map:
|
||||
return fmt.Errorf("pointers to maps are not supported")
|
||||
}
|
||||
case types.Array:
|
||||
return fmt.Errorf("fixed-size arrays are not supported")
|
||||
case types.Slice:
|
||||
elem := util.NativeType(t.Elem)
|
||||
switch elem.Kind {
|
||||
case types.Pointer:
|
||||
return fmt.Errorf("lists of pointers are not supported")
|
||||
case types.Slice:
|
||||
if util.NativeType(elem.Elem) != types.Byte {
|
||||
return fmt.Errorf("lists of lists are not supported")
|
||||
}
|
||||
case types.Map:
|
||||
return fmt.Errorf("lists of maps are not supported")
|
||||
}
|
||||
case types.Map:
|
||||
key := util.NativeType(t.Key)
|
||||
if key != types.String {
|
||||
return fmt.Errorf("maps with non-string keys are not supported")
|
||||
}
|
||||
elem := util.NativeType(t.Elem)
|
||||
switch elem.Kind {
|
||||
case types.Pointer:
|
||||
return fmt.Errorf("maps of pointers are not supported")
|
||||
case types.Map:
|
||||
return fmt.Errorf("maps of maps are not supported")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("kind %v is not supported", t.Kind)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// discoverStruct walks a struct type recursively.
|
||||
func (td *typeDiscoverer) discoverStruct(thisNode *typeNode, fldPath *field.Path) error {
|
||||
var fields []*childNode
|
||||
@@ -589,11 +594,7 @@ func (td *typeDiscoverer) discoverStruct(thisNode *typeNode, fldPath *field.Path
|
||||
klog.V(6).InfoS("no field-attached validations", "field", childPath)
|
||||
} else {
|
||||
klog.V(5).InfoS("found field-attached validations", "n", validations.Len(), "field", childPath)
|
||||
// TODO: This check is placed here to allow map-of-slices fields to exist in the type
|
||||
// system, while preventing validation on them since that functionality is not yet
|
||||
// implemented. Once validation support for map-of-slices is added, this check should
|
||||
// be removed.
|
||||
if util.NativeType(childType).Kind == types.Map && util.NativeType(childType).Elem.Kind == types.Slice {
|
||||
if util.NonPointer(util.NativeType(childType)).Kind == types.Map && util.NonPointer(util.NativeType(childType)).Elem.Kind == types.Slice {
|
||||
return fmt.Errorf("field %s: validation for map of slices is not supported", childPath)
|
||||
}
|
||||
child.fieldValidations.Add(validations)
|
||||
@@ -603,7 +604,7 @@ func (td *typeDiscoverer) discoverStruct(thisNode *typeNode, fldPath *field.Path
|
||||
}
|
||||
|
||||
// Handle non-included types.
|
||||
switch nonPtrType(childType).Kind {
|
||||
switch util.NonPointer(childType).Kind {
|
||||
case types.Struct, types.Alias:
|
||||
if child.node == nil { // a non-included type
|
||||
if !child.fieldValidations.OpaqueType {
|
||||
@@ -728,14 +729,6 @@ func (td *typeDiscoverer) discoverStruct(thisNode *typeNode, fldPath *field.Path
|
||||
return nil
|
||||
}
|
||||
|
||||
// nonPtrType removes any pointerness from the type.
|
||||
func nonPtrType(t *types.Type) *types.Type {
|
||||
for t.Kind == types.Pointer {
|
||||
t = t.Elem
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// getValidationFunctionName looks up the name of the specified type's
|
||||
// validation function.
|
||||
//
|
||||
@@ -1009,8 +1002,6 @@ func (g *genValidations) emitValidationForChild(c *generator.Context, thisChild
|
||||
bufsw := sw.Dup(buf)
|
||||
|
||||
validations := fld.fieldValidations
|
||||
|
||||
// fldRatchetingChecked is used to avoid emitting the ratcheting check multiple times.
|
||||
fldRatchetingChecked := false
|
||||
if !validations.Empty() {
|
||||
emitComments(validations.Comments, bufsw)
|
||||
@@ -1146,9 +1137,15 @@ func emitRatchetingCheck(c *generator.Context, t *types.Type, sw *generator.Snip
|
||||
}
|
||||
// If the type is a builtin, we can use a simpler equality check when they are not nil.
|
||||
if util.IsDirectComparable(util.NonPointer(util.NativeType(t))) {
|
||||
_, exprPfx, _ := getLeafTypeAndPrefixes(t)
|
||||
targs["exprPfx"] = exprPfx
|
||||
sw.Do("if op.Type == $.operation.Update|raw$ && (obj == oldObj || (obj != nil && oldObj != nil && $.exprPfx$obj == $.exprPfx$oldObj)) {\n", targs)
|
||||
// We should never get anything but pointers here, since every other
|
||||
// nilable type is not Comparable.
|
||||
//
|
||||
// This condition looks overly complex, but each case is needed:
|
||||
// - obj == oldObj : handle pointers which are nil in old and new
|
||||
// - obj != nil : handle optional fields which are updated to nil
|
||||
// - oldObj != nil : handle optional fields which are updated from nil
|
||||
// - *obj == *oldObj : compare values
|
||||
sw.Do("if op.Type == $.operation.Update|raw$ && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {\n", targs)
|
||||
} else {
|
||||
targs["equality"] = mkSymbolArgs(c, equalityPkgSymbols)
|
||||
sw.Do("if op.Type == $.operation.Update|raw$ && $.equality.Semantic|raw$.DeepEqual(obj, oldObj) {\n", targs)
|
||||
@@ -1341,6 +1338,8 @@ func toGolangSourceDataLiteral(sw *generator.SnippetWriter, c *generator.Context
|
||||
sw.Do("$.|raw$", v)
|
||||
case types.Member:
|
||||
sw.Do("obj."+v.Name, nil)
|
||||
case *types.Member:
|
||||
sw.Do("obj."+v.Name, nil)
|
||||
case validators.Identifier:
|
||||
sw.Do("$.|raw$", c.Universe.Type(types.Name(v)))
|
||||
case *validators.Identifier:
|
||||
|
||||
@@ -22,59 +22,53 @@ import (
|
||||
"k8s.io/gengo/v2/types"
|
||||
)
|
||||
|
||||
func TestGetLeafTypeAndPrefixes(t *testing.T) {
|
||||
stringType := &types.Type{
|
||||
// gengo has `PointerTo()` but not the rest, so keep this here for consistency.
|
||||
func ptrTo(t *types.Type) *types.Type {
|
||||
return &types.Type{
|
||||
Name: types.Name{
|
||||
Package: "",
|
||||
Name: "string",
|
||||
Name: "*" + t.Name.String(),
|
||||
},
|
||||
Kind: types.Builtin,
|
||||
Kind: types.Pointer,
|
||||
Elem: t,
|
||||
}
|
||||
}
|
||||
|
||||
ptrTo := func(t *types.Type) *types.Type {
|
||||
return &types.Type{
|
||||
Name: types.Name{
|
||||
Package: "",
|
||||
Name: "*" + t.Name.String(),
|
||||
},
|
||||
Kind: types.Pointer,
|
||||
Elem: t,
|
||||
}
|
||||
func sliceOf(t *types.Type) *types.Type {
|
||||
return &types.Type{
|
||||
Name: types.Name{
|
||||
Package: "",
|
||||
Name: "[]" + t.Name.String(),
|
||||
},
|
||||
Kind: types.Slice,
|
||||
Elem: t,
|
||||
}
|
||||
}
|
||||
|
||||
sliceOf := func(t *types.Type) *types.Type {
|
||||
return &types.Type{
|
||||
Name: types.Name{
|
||||
Package: "",
|
||||
Name: "[]" + t.Name.String(),
|
||||
},
|
||||
Kind: types.Slice,
|
||||
Elem: t,
|
||||
}
|
||||
func mapOf(t *types.Type) *types.Type {
|
||||
return &types.Type{
|
||||
Name: types.Name{
|
||||
Package: "",
|
||||
Name: "map[string]" + t.Name.String(),
|
||||
},
|
||||
Kind: types.Map,
|
||||
Key: types.String,
|
||||
Elem: t,
|
||||
}
|
||||
}
|
||||
|
||||
mapOf := func(t *types.Type) *types.Type {
|
||||
return &types.Type{
|
||||
Name: types.Name{
|
||||
Package: "",
|
||||
Name: "map[string]" + t.Name.String(),
|
||||
},
|
||||
Kind: types.Map,
|
||||
Key: stringType,
|
||||
Elem: t,
|
||||
}
|
||||
func aliasOf(name string, t *types.Type) *types.Type {
|
||||
return &types.Type{
|
||||
Name: types.Name{
|
||||
Package: "",
|
||||
Name: "Alias_" + name,
|
||||
},
|
||||
Kind: types.Alias,
|
||||
Underlying: t,
|
||||
}
|
||||
}
|
||||
|
||||
aliasOf := func(name string, t *types.Type) *types.Type {
|
||||
return &types.Type{
|
||||
Name: types.Name{
|
||||
Package: "",
|
||||
Name: "Alias_" + name,
|
||||
},
|
||||
Kind: types.Alias,
|
||||
Underlying: t,
|
||||
}
|
||||
}
|
||||
func TestGetLeafTypeAndPrefixes(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
in *types.Type
|
||||
@@ -83,278 +77,278 @@ func TestGetLeafTypeAndPrefixes(t *testing.T) {
|
||||
expectedExprPfx string
|
||||
}{{
|
||||
// string
|
||||
in: stringType,
|
||||
expectedType: stringType,
|
||||
in: types.String,
|
||||
expectedType: types.String,
|
||||
expectedTypePfx: "*",
|
||||
expectedExprPfx: "&",
|
||||
}, {
|
||||
// *string
|
||||
in: ptrTo(stringType),
|
||||
expectedType: stringType,
|
||||
in: ptrTo(types.String),
|
||||
expectedType: types.String,
|
||||
expectedTypePfx: "*",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// **string
|
||||
in: ptrTo(ptrTo(stringType)),
|
||||
expectedType: stringType,
|
||||
in: ptrTo(ptrTo(types.String)),
|
||||
expectedType: types.String,
|
||||
expectedTypePfx: "*",
|
||||
expectedExprPfx: "*",
|
||||
}, {
|
||||
// ***string
|
||||
in: ptrTo(ptrTo(ptrTo(stringType))),
|
||||
expectedType: stringType,
|
||||
in: ptrTo(ptrTo(ptrTo(types.String))),
|
||||
expectedType: types.String,
|
||||
expectedTypePfx: "*",
|
||||
expectedExprPfx: "**",
|
||||
}, {
|
||||
// []string
|
||||
in: sliceOf(stringType),
|
||||
expectedType: sliceOf(stringType),
|
||||
in: sliceOf(types.String),
|
||||
expectedType: sliceOf(types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// *[]string
|
||||
in: ptrTo(sliceOf(stringType)),
|
||||
expectedType: sliceOf(stringType),
|
||||
in: ptrTo(sliceOf(types.String)),
|
||||
expectedType: sliceOf(types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "*",
|
||||
}, {
|
||||
// **[]string
|
||||
in: ptrTo(ptrTo(sliceOf(stringType))),
|
||||
expectedType: sliceOf(stringType),
|
||||
in: ptrTo(ptrTo(sliceOf(types.String))),
|
||||
expectedType: sliceOf(types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "**",
|
||||
}, {
|
||||
// ***[]string
|
||||
in: ptrTo(ptrTo(ptrTo(sliceOf(stringType)))),
|
||||
expectedType: sliceOf(stringType),
|
||||
in: ptrTo(ptrTo(ptrTo(sliceOf(types.String)))),
|
||||
expectedType: sliceOf(types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "***",
|
||||
}, {
|
||||
// map[string]string
|
||||
in: mapOf(stringType),
|
||||
expectedType: mapOf(stringType),
|
||||
in: mapOf(types.String),
|
||||
expectedType: mapOf(types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// *map[string]string
|
||||
in: ptrTo(mapOf(stringType)),
|
||||
expectedType: mapOf(stringType),
|
||||
in: ptrTo(mapOf(types.String)),
|
||||
expectedType: mapOf(types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "*",
|
||||
}, {
|
||||
// **map[string]string
|
||||
in: ptrTo(ptrTo(mapOf(stringType))),
|
||||
expectedType: mapOf(stringType),
|
||||
in: ptrTo(ptrTo(mapOf(types.String))),
|
||||
expectedType: mapOf(types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "**",
|
||||
}, {
|
||||
// ***map[string]string
|
||||
in: ptrTo(ptrTo(ptrTo(mapOf(stringType)))),
|
||||
expectedType: mapOf(stringType),
|
||||
in: ptrTo(ptrTo(ptrTo(mapOf(types.String)))),
|
||||
expectedType: mapOf(types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "***",
|
||||
}, {
|
||||
// alias of string
|
||||
in: aliasOf("s", stringType),
|
||||
expectedType: aliasOf("s", stringType),
|
||||
in: aliasOf("s", types.String),
|
||||
expectedType: aliasOf("s", types.String),
|
||||
expectedTypePfx: "*",
|
||||
expectedExprPfx: "&",
|
||||
}, {
|
||||
// alias of *string
|
||||
in: aliasOf("ps", ptrTo(stringType)),
|
||||
expectedType: aliasOf("ps", stringType),
|
||||
in: aliasOf("ps", ptrTo(types.String)),
|
||||
expectedType: aliasOf("ps", types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// alias of **string
|
||||
in: aliasOf("pps", ptrTo(ptrTo(stringType))),
|
||||
expectedType: aliasOf("pps", stringType),
|
||||
in: aliasOf("pps", ptrTo(ptrTo(types.String))),
|
||||
expectedType: aliasOf("pps", types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// alias of ***string
|
||||
in: aliasOf("ppps", ptrTo(ptrTo(ptrTo(stringType)))),
|
||||
expectedType: aliasOf("ppps", stringType),
|
||||
in: aliasOf("ppps", ptrTo(ptrTo(ptrTo(types.String)))),
|
||||
expectedType: aliasOf("ppps", types.String),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// alias of []string
|
||||
in: aliasOf("ls", sliceOf(stringType)),
|
||||
expectedType: aliasOf("ls", sliceOf(stringType)),
|
||||
in: aliasOf("ls", sliceOf(types.String)),
|
||||
expectedType: aliasOf("ls", sliceOf(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// alias of *[]string
|
||||
in: aliasOf("pls", ptrTo(sliceOf(stringType))),
|
||||
expectedType: aliasOf("pls", sliceOf(stringType)),
|
||||
in: aliasOf("pls", ptrTo(sliceOf(types.String))),
|
||||
expectedType: aliasOf("pls", sliceOf(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// alias of **[]string
|
||||
in: aliasOf("ppls", ptrTo(ptrTo(sliceOf(stringType)))),
|
||||
expectedType: aliasOf("ppls", sliceOf(stringType)),
|
||||
in: aliasOf("ppls", ptrTo(ptrTo(sliceOf(types.String)))),
|
||||
expectedType: aliasOf("ppls", sliceOf(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// alias of ***[]string
|
||||
in: aliasOf("pppls", ptrTo(ptrTo(ptrTo(sliceOf(stringType))))),
|
||||
expectedType: aliasOf("pppls", sliceOf(stringType)),
|
||||
in: aliasOf("pppls", ptrTo(ptrTo(ptrTo(sliceOf(types.String))))),
|
||||
expectedType: aliasOf("pppls", sliceOf(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// alias of map[string]string
|
||||
in: aliasOf("ms", mapOf(stringType)),
|
||||
expectedType: aliasOf("ms", mapOf(stringType)),
|
||||
in: aliasOf("ms", mapOf(types.String)),
|
||||
expectedType: aliasOf("ms", mapOf(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// alias of *map[string]string
|
||||
in: aliasOf("pms", ptrTo(mapOf(stringType))),
|
||||
expectedType: aliasOf("pms", mapOf(stringType)),
|
||||
in: aliasOf("pms", ptrTo(mapOf(types.String))),
|
||||
expectedType: aliasOf("pms", mapOf(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// alias of **map[string]string
|
||||
in: aliasOf("ppms", ptrTo(ptrTo(mapOf(stringType)))),
|
||||
expectedType: aliasOf("ppms", mapOf(stringType)),
|
||||
in: aliasOf("ppms", ptrTo(ptrTo(mapOf(types.String)))),
|
||||
expectedType: aliasOf("ppms", mapOf(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// alias of ***map[string]string
|
||||
in: aliasOf("pppms", ptrTo(ptrTo(ptrTo(mapOf(stringType))))),
|
||||
expectedType: aliasOf("pppms", mapOf(stringType)),
|
||||
in: aliasOf("pppms", ptrTo(ptrTo(ptrTo(mapOf(types.String))))),
|
||||
expectedType: aliasOf("pppms", mapOf(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// *alias-of-string
|
||||
in: ptrTo(aliasOf("s", stringType)),
|
||||
expectedType: aliasOf("s", stringType),
|
||||
in: ptrTo(aliasOf("s", types.String)),
|
||||
expectedType: aliasOf("s", types.String),
|
||||
expectedTypePfx: "*",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// **alias-of-string
|
||||
in: ptrTo(ptrTo(aliasOf("s", stringType))),
|
||||
expectedType: aliasOf("s", stringType),
|
||||
in: ptrTo(ptrTo(aliasOf("s", types.String))),
|
||||
expectedType: aliasOf("s", types.String),
|
||||
expectedTypePfx: "*",
|
||||
expectedExprPfx: "*",
|
||||
}, {
|
||||
// ***alias-of-string
|
||||
in: ptrTo(ptrTo(ptrTo(aliasOf("s", stringType)))),
|
||||
expectedType: aliasOf("s", stringType),
|
||||
in: ptrTo(ptrTo(ptrTo(aliasOf("s", types.String)))),
|
||||
expectedType: aliasOf("s", types.String),
|
||||
expectedTypePfx: "*",
|
||||
expectedExprPfx: "**",
|
||||
}, {
|
||||
// []alias-of-string
|
||||
in: sliceOf(aliasOf("s", stringType)),
|
||||
expectedType: sliceOf(aliasOf("s", stringType)),
|
||||
in: sliceOf(aliasOf("s", types.String)),
|
||||
expectedType: sliceOf(aliasOf("s", types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// *[]alias-of-string
|
||||
in: ptrTo(sliceOf(aliasOf("s", stringType))),
|
||||
expectedType: sliceOf(aliasOf("s", stringType)),
|
||||
in: ptrTo(sliceOf(aliasOf("s", types.String))),
|
||||
expectedType: sliceOf(aliasOf("s", types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "*",
|
||||
}, {
|
||||
// **[]alias-of-string
|
||||
in: ptrTo(ptrTo(sliceOf(aliasOf("s", stringType)))),
|
||||
expectedType: sliceOf(aliasOf("s", stringType)),
|
||||
in: ptrTo(ptrTo(sliceOf(aliasOf("s", types.String)))),
|
||||
expectedType: sliceOf(aliasOf("s", types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "**",
|
||||
}, {
|
||||
// ***[]alias-of-string
|
||||
in: ptrTo(ptrTo(ptrTo(sliceOf(aliasOf("s", stringType))))),
|
||||
expectedType: sliceOf(aliasOf("s", stringType)),
|
||||
in: ptrTo(ptrTo(ptrTo(sliceOf(aliasOf("s", types.String))))),
|
||||
expectedType: sliceOf(aliasOf("s", types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "***",
|
||||
}, {
|
||||
// map[string]alias-of-string
|
||||
in: mapOf(aliasOf("s", stringType)),
|
||||
expectedType: mapOf(aliasOf("s", stringType)),
|
||||
in: mapOf(aliasOf("s", types.String)),
|
||||
expectedType: mapOf(aliasOf("s", types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// *map[string]alias-of-string
|
||||
in: ptrTo(mapOf(aliasOf("s", stringType))),
|
||||
expectedType: mapOf(aliasOf("s", stringType)),
|
||||
in: ptrTo(mapOf(aliasOf("s", types.String))),
|
||||
expectedType: mapOf(aliasOf("s", types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "*",
|
||||
}, {
|
||||
// **map[string]alias-of-string
|
||||
in: ptrTo(ptrTo(mapOf(aliasOf("s", stringType)))),
|
||||
expectedType: mapOf(aliasOf("s", stringType)),
|
||||
in: ptrTo(ptrTo(mapOf(aliasOf("s", types.String)))),
|
||||
expectedType: mapOf(aliasOf("s", types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "**",
|
||||
}, {
|
||||
// ***map[string]alias-of-string
|
||||
in: ptrTo(ptrTo(ptrTo(mapOf(aliasOf("s", stringType))))),
|
||||
expectedType: mapOf(aliasOf("s", stringType)),
|
||||
in: ptrTo(ptrTo(ptrTo(mapOf(aliasOf("s", types.String))))),
|
||||
expectedType: mapOf(aliasOf("s", types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "***",
|
||||
}, {
|
||||
// *alias-of-*string
|
||||
in: ptrTo(aliasOf("ps", ptrTo(stringType))),
|
||||
expectedType: aliasOf("ps", ptrTo(stringType)),
|
||||
in: ptrTo(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedType: aliasOf("ps", ptrTo(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "*",
|
||||
}, {
|
||||
// **alias-of-*string
|
||||
in: ptrTo(ptrTo(aliasOf("ps", ptrTo(stringType)))),
|
||||
expectedType: aliasOf("ps", ptrTo(stringType)),
|
||||
in: ptrTo(ptrTo(aliasOf("ps", ptrTo(types.String)))),
|
||||
expectedType: aliasOf("ps", ptrTo(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "**",
|
||||
}, {
|
||||
// ***alias-of-*string
|
||||
in: ptrTo(ptrTo(ptrTo(aliasOf("ps", ptrTo(stringType))))),
|
||||
expectedType: aliasOf("ps", ptrTo(stringType)),
|
||||
in: ptrTo(ptrTo(ptrTo(aliasOf("ps", ptrTo(types.String))))),
|
||||
expectedType: aliasOf("ps", ptrTo(types.String)),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "***",
|
||||
}, {
|
||||
// []alias-of-*string
|
||||
in: sliceOf(aliasOf("ps", ptrTo(stringType))),
|
||||
expectedType: sliceOf(aliasOf("ps", ptrTo(stringType))),
|
||||
in: sliceOf(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedType: sliceOf(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// *[]alias-of-*string
|
||||
in: ptrTo(sliceOf(aliasOf("ps", ptrTo(stringType)))),
|
||||
expectedType: sliceOf(aliasOf("ps", ptrTo(stringType))),
|
||||
in: ptrTo(sliceOf(aliasOf("ps", ptrTo(types.String)))),
|
||||
expectedType: sliceOf(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "*",
|
||||
}, {
|
||||
// **[]alias-of-*string
|
||||
in: ptrTo(ptrTo(sliceOf(aliasOf("ps", ptrTo(stringType))))),
|
||||
expectedType: sliceOf(aliasOf("ps", ptrTo(stringType))),
|
||||
in: ptrTo(ptrTo(sliceOf(aliasOf("ps", ptrTo(types.String))))),
|
||||
expectedType: sliceOf(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "**",
|
||||
}, {
|
||||
// ***[]alias-of-*string
|
||||
in: ptrTo(ptrTo(ptrTo(sliceOf(aliasOf("ps", ptrTo(stringType)))))),
|
||||
expectedType: sliceOf(aliasOf("ps", ptrTo(stringType))),
|
||||
in: ptrTo(ptrTo(ptrTo(sliceOf(aliasOf("ps", ptrTo(types.String)))))),
|
||||
expectedType: sliceOf(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "***",
|
||||
}, {
|
||||
// map[string]alias-of-*string
|
||||
in: mapOf(aliasOf("ps", ptrTo(stringType))),
|
||||
expectedType: mapOf(aliasOf("ps", ptrTo(stringType))),
|
||||
in: mapOf(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedType: mapOf(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "",
|
||||
}, {
|
||||
// *map[string]alias-of-*string
|
||||
in: ptrTo(mapOf(aliasOf("ps", ptrTo(stringType)))),
|
||||
expectedType: mapOf(aliasOf("ps", ptrTo(stringType))),
|
||||
in: ptrTo(mapOf(aliasOf("ps", ptrTo(types.String)))),
|
||||
expectedType: mapOf(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "*",
|
||||
}, {
|
||||
// **map[string]alias-of-*string
|
||||
in: ptrTo(ptrTo(mapOf(aliasOf("ps", ptrTo(stringType))))),
|
||||
expectedType: mapOf(aliasOf("ps", ptrTo(stringType))),
|
||||
in: ptrTo(ptrTo(mapOf(aliasOf("ps", ptrTo(types.String))))),
|
||||
expectedType: mapOf(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "**",
|
||||
}, {
|
||||
// ***map[string]alias-of-*string
|
||||
in: ptrTo(ptrTo(ptrTo(mapOf(aliasOf("ps", ptrTo(stringType)))))),
|
||||
expectedType: mapOf(aliasOf("ps", ptrTo(stringType))),
|
||||
in: ptrTo(ptrTo(ptrTo(mapOf(aliasOf("ps", ptrTo(types.String)))))),
|
||||
expectedType: mapOf(aliasOf("ps", ptrTo(types.String))),
|
||||
expectedTypePfx: "",
|
||||
expectedExprPfx: "***",
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user