| // Copyright 2018 The Bazel Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package starlarkstruct_test |
| |
| import ( |
| "fmt" |
| "path/filepath" |
| "testing" |
| |
| "go.starlark.net/starlark" |
| "go.starlark.net/resolve" |
| "go.starlark.net/starlarkstruct" |
| "go.starlark.net/starlarktest" |
| ) |
| |
| func init() { |
| // The tests make extensive use of these not-yet-standard features. |
| resolve.AllowLambda = true |
| resolve.AllowNestedDef = true |
| resolve.AllowFloat = true |
| resolve.AllowSet = true |
| } |
| |
| func Test(t *testing.T) { |
| testdata := starlarktest.DataFile("starlarkstruct", ".") |
| thread := &starlark.Thread{Load: load} |
| starlarktest.SetReporter(thread, t) |
| filename := filepath.Join(testdata, "testdata/struct.star") |
| predeclared := starlark.StringDict{ |
| "struct": starlark.NewBuiltin("struct", starlarkstruct.Make), |
| "gensym": starlark.NewBuiltin("gensym", gensym), |
| } |
| if _, err := starlark.ExecFile(thread, filename, nil, predeclared); err != nil { |
| if err, ok := err.(*starlark.EvalError); ok { |
| t.Fatal(err.Backtrace()) |
| } |
| t.Fatal(err) |
| } |
| } |
| |
| // load implements the 'load' operation as used in the evaluator tests. |
| func load(thread *starlark.Thread, module string) (starlark.StringDict, error) { |
| if module == "assert.star" { |
| return starlarktest.LoadAssertModule() |
| } |
| return nil, fmt.Errorf("load not implemented") |
| } |
| |
| // gensym is a built-in function that generates a unique symbol. |
| func gensym(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { |
| var name string |
| if err := starlark.UnpackArgs("gensym", args, kwargs, "name", &name); err != nil { |
| return nil, err |
| } |
| return &symbol{name: name}, nil |
| } |
| |
| // A symbol is a distinct value that acts as a constructor of "branded" |
| // struct instances, like a class symbol in Python or a "provider" in Bazel. |
| type symbol struct{ name string } |
| |
| var _ starlark.Callable = (*symbol)(nil) |
| |
| func (sym *symbol) Name() string { return sym.name } |
| func (sym *symbol) String() string { return sym.name } |
| func (sym *symbol) Type() string { return "symbol" } |
| func (sym *symbol) Freeze() {} // immutable |
| func (sym *symbol) Truth() starlark.Bool { return starlark.True } |
| func (sym *symbol) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", sym.Type()) } |
| |
| func (sym *symbol) CallInternal(thread *starlark.Thread, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { |
| if len(args) > 0 { |
| return nil, fmt.Errorf("%s: unexpected positional arguments", sym) |
| } |
| return starlarkstruct.FromKeywords(sym, kwargs), nil |
| } |