pulumi/pkg/tokens/decors_test.go
joeduffy 5260ff9313 Add a crazy recursive parsing test...and fix some bugs
This change completes my testing of decorator parsing for now.  It tests the token
`*[]map[string]map[()*(bool,string,test/package:test/module/Crazy)number][][]test/package:test/module/Crazy`.

This turned up some bugs, most notably in the way we returned the "full" token for
the parsed types.  We need to extract the subset of the token consumed by the parsing
routine, rather than the entire thing.  To do this, we introduce a tokenBuffer type
that allows for convenient parsing of tokens (eating, advancing, extraction, etc).
2017-01-24 05:25:08 -08:00

229 lines
6.4 KiB
Go

// Copyright 2016 Marapongo, Inc. All rights reserved.
package tokens
import (
"testing"
"github.com/stretchr/testify/assert"
)
func newTestTypeToken(nm string) Type {
pkg := NewPackageToken("test/package")
mod := NewModuleToken(pkg, "test/module")
return NewTypeToken(mod, TypeName(nm))
}
func TestArrayTypes(t *testing.T) {
// Test simple primitives.
for _, prim := range []string{"any", "bool", "string", "number"} {
ptr := NewArrayTypeToken(Type(prim))
assert.True(t, ptr.Array(), "Expected array type token to be an array")
parsed := ParseArrayType(ptr)
assert.Equal(t, prim, string(parsed.Elem))
}
// Test more complex array type elements.
class := newTestTypeToken("ArrayTest")
ptr := NewArrayTypeToken(class)
assert.True(t, ptr.Array(), "Expected array type token to be an array")
parsed := ParseArrayType(ptr)
assert.Equal(t, string(class), string(parsed.Elem))
}
func TestPointerTypes(t *testing.T) {
// Test simple primitives.
for _, prim := range []string{"any", "bool", "string", "number"} {
ptr := NewPointerTypeToken(Type(prim))
assert.True(t, ptr.Pointer(), "Expected pointer type token to be a pointer")
parsed := ParsePointerType(ptr)
assert.Equal(t, prim, string(parsed.Elem))
}
// Test more complex pointer type elements.
class := newTestTypeToken("PointerTest")
ptr := NewPointerTypeToken(class)
assert.True(t, ptr.Pointer(), "Expected pointer type token to be a pointer")
parsed := ParsePointerType(ptr)
assert.Equal(t, string(class), string(parsed.Elem))
}
func TestMapTypes(t *testing.T) {
// Test simple primitives.
for _, key := range []string{"string", "bool", "number"} {
for _, elem := range []string{"any", "bool", "string", "number"} {
ptr := NewMapTypeToken(Type(key), Type(elem))
assert.True(t, ptr.Map(), "Expected map type token to be a map")
parsed := ParseMapType(ptr)
assert.Equal(t, key, string(parsed.Key))
assert.Equal(t, elem, string(parsed.Elem))
}
}
// Test more complex map type elements.
for _, key := range []string{"string", "bool", "number"} {
class := newTestTypeToken("MapTest")
ptr := NewMapTypeToken(Type(key), class)
assert.True(t, ptr.Map(), "Expected map type token to be a map")
parsed := ParseMapType(ptr)
assert.Equal(t, key, string(parsed.Key))
assert.Equal(t, string(class), string(parsed.Elem))
}
}
func TestFunctionTypes(t *testing.T) {
class := newTestTypeToken("FuncTest")
types := []string{"any", "bool", "string", "number", string(class)}
rtypes := append([]string{""}, types...)
for _, retty := range rtypes {
// If the return exists, use it.
var ret *Type
if retty != "" {
r := Type(retty)
ret = &r
}
// Do [0...4) parameter counts.
for i := 0; i < 4; i++ {
ixs := make([]int, i)
for {
// Append the current set to the params.
var params []Type
for _, ix := range ixs {
params = append(params, Type(types[ix]))
}
// Check the result.
fnc := NewFunctionTypeToken(params, ret)
assert.True(t, fnc.Function(), "Expected function type token to be a function")
parsed := ParseFunctionType(fnc)
assert.Equal(t, len(params), len(parsed.Parameters))
for i, param := range parsed.Parameters {
assert.Equal(t, string(params[i]), string(param))
}
if ret == nil {
assert.Nil(t, parsed.Return)
} else {
assert.NotNil(t, parsed.Return)
assert.Equal(t, string(*ret), string(*parsed.Return))
}
// Now rotate the parameters (or break if done).
done := (i == 0)
for j := 0; j < i; j++ {
ixs[j]++
if ixs[j] == len(types) {
// Reset the counter, and keep incrementing.
ixs[j] = 0
if j == i-1 {
// Done altogether; break break break!
done = true
}
} else {
// The lower indices aren't exhausted, stop incrementing.
break
}
}
if done {
break
}
}
}
}
}
func TestComplexTypes(t *testing.T) {
// Create a crazy nested type and make sure they parse correctly; essentially:
// *[]map[string]map[()*(bool,string,Crazy)number][][]Crazy
// or, in the fully qualified form:
// *[]map[string]map[()*(bool,string,test/package:test/module/Crazy)number][][]test/package:test/module/Crazy
// which should parse as
// Pointer
// Elem=Array
// Elem=Map
// Key=string
// Elem=Map
// Key=Func
// Params=()
// Return=Pointer
// Func
// Params=
// bool
// string
// Crazy
// Return=number
// Elem=Array
// Elem=Array
// Elem=Crazy
crazy := newTestTypeToken("Crazy")
number := Type("number")
ptrret := NewPointerTypeToken(NewFunctionTypeToken([]Type{"bool", "string", crazy}, &number))
ptr := NewPointerTypeToken(
NewArrayTypeToken(
NewMapTypeToken(
Type("string"),
NewMapTypeToken(
NewFunctionTypeToken(
[]Type{},
&ptrret,
),
NewArrayTypeToken(
NewArrayTypeToken(
crazy,
),
),
),
),
),
)
assert.True(t, ptr.Pointer(), "Expected pointer type token to be an pointer")
p1 := ParsePointerType(ptr) // Pointer<Array>
{
assert.True(t, p1.Elem.Array())
p2 := ParseArrayType(p1.Elem) // Array<Map>
{
assert.True(t, p2.Elem.Map())
p3 := ParseMapType(p2.Elem) // Map<string, Map>
{
assert.Equal(t, "string", string(p3.Key))
assert.True(t, p3.Elem.Map())
p4 := ParseMapType(p3.Elem) // Map<Func, Array>
{
assert.True(t, p4.Key.Function())
p5 := ParseFunctionType(p4.Key) // Func<(), Pointer>
{
assert.Equal(t, 0, len(p5.Parameters))
assert.NotNil(t, p5.Return)
assert.True(t, (*p5.Return).Pointer())
p6 := ParsePointerType(*p5.Return) // Pointer<Func>
{
assert.True(t, p6.Elem.Function())
p7 := ParseFunctionType(p6.Elem) // Func<(bool,string,Crazy), number>
{
assert.Equal(t, 3, len(p7.Parameters))
assert.Equal(t, "bool", string(p7.Parameters[0]))
assert.Equal(t, "string", string(p7.Parameters[1]))
assert.Equal(t, string(crazy), string(p7.Parameters[2]))
assert.NotNil(t, p7.Return)
assert.Equal(t, "number", string(*p7.Return))
}
}
}
assert.True(t, p4.Elem.Array())
p8 := ParseArrayType(p4.Elem) // Array<Array>
{
assert.True(t, p8.Elem.Array())
p9 := ParseArrayType(p8.Elem) // Array<Crazy>
{
assert.Equal(t, string(crazy), string(p9.Elem))
}
}
}
}
}
}
}