blob: 76f14dc671c5ec634f09d6ab20688c0d28ec5654 [file] [log] [blame]
// Copyright 2019 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package typed
import (
"testing"
"go.starlark.net/resolve"
"go.starlark.net/starlark"
"go.chromium.org/luci/starlark/starlarktest"
)
func init() {
resolve.AllowLambda = true
resolve.AllowNestedDef = true
}
func TestAllStarlark(t *testing.T) {
t.Parallel()
var (
listLetters = []string{"T", "K", "L", "M"}
dictLetters = []string{"K", "V", "T", "M"}
)
allocLetter := func(letters *[]string) (l string) {
if len(*letters) == 0 {
return "X"
}
l, *letters = (*letters)[0], (*letters)[1:]
return
}
converter := func(th *starlark.Thread, cb starlark.Callable, letters *[]string) Converter {
// Cache *callbackConverter so that all converters build from same
// callback have same address. This is used to test list.extend fast
// path.
if th.Local("converters") == nil {
th.SetLocal("converters", map[starlark.Callable]Converter{})
}
converters := th.Local("converters").(map[starlark.Callable]Converter)
if converters[cb] == nil {
converters[cb] = &callbackConverter{th, cb, allocLetter(letters)}
}
return converters[cb]
}
starlarktest.RunTests(t, starlarktest.Options{
TestsDir: "testdata",
Predeclared: starlark.StringDict{
// typed_list(cb, list): new typed.List using the callback as converter.
"typed_list": starlark.NewBuiltin("typed_list", func(th *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var cb starlark.Callable
var vals starlark.Value
if err := starlark.UnpackPositionalArgs("typed_list", args, kwargs, 2, &cb, &vals); err != nil {
return nil, err
}
return AsTypedList(converter(th, cb, &listLetters), vals)
}),
// typed_dict(key_cb, val_cb): new typed.Dict using callbacks as converters.
"typed_dict": starlark.NewBuiltin("typed_dict", func(th *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var keyCB starlark.Callable
var valCB starlark.Callable
var items starlark.Value
if err := starlark.UnpackPositionalArgs("typed_dict", args, kwargs, 3, &keyCB, &valCB, &items); err != nil {
return nil, err
}
return AsTypedDict(
converter(th, keyCB, &dictLetters),
converter(th, valCB, &dictLetters), items)
}),
},
})
}
type callbackConverter struct {
th *starlark.Thread
cb starlark.Callable
typ string
}
func (c *callbackConverter) Convert(x starlark.Value) (starlark.Value, error) {
return starlark.Call(c.th, c.cb, starlark.Tuple{x}, nil)
}
func (c *callbackConverter) Type() string {
return c.typ
}