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).
228 lines
6.4 KiB
Go
228 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))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|