// Copyright 2023 Google Inc. All rights reserved. // // 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 starlark_import import ( "reflect" "testing" "go.starlark.net/starlark" ) func createStarlarkValue(t *testing.T, code string) starlark.Value { t.Helper() result, err := starlark.ExecFile(&starlark.Thread{}, "main.bzl", "x = "+code, builtins) if err != nil { panic(err) } return result["x"] } func TestUnmarshalConcreteType(t *testing.T) { x, err := Unmarshal[string](createStarlarkValue(t, `"foo"`)) if err != nil { t.Error(err) return } if x != "foo" { t.Errorf(`Expected "foo", got %q`, x) } } func TestUnmarshalConcreteTypeWithInterfaces(t *testing.T) { x, err := Unmarshal[map[string]map[string]interface{}](createStarlarkValue(t, `{"foo": {"foo2": "foo3"}, "bar": {"bar2": ["bar3"]}}`)) if err != nil { t.Error(err) return } expected := map[string]map[string]interface{}{ "foo": {"foo2": "foo3"}, "bar": {"bar2": []string{"bar3"}}, } if !reflect.DeepEqual(x, expected) { t.Errorf(`Expected %v, got %v`, expected, x) } } func TestUnmarshalToStarlarkValue(t *testing.T) { x, err := Unmarshal[map[string]starlark.Value](createStarlarkValue(t, `{"foo": "Hi", "bar": None}`)) if err != nil { t.Error(err) return } if x["foo"].(starlark.String).GoString() != "Hi" { t.Errorf("Expected \"Hi\", got: %q", x["foo"].(starlark.String).GoString()) } if x["bar"].Type() != "NoneType" { t.Errorf("Expected \"NoneType\", got: %q", x["bar"].Type()) } } func TestUnmarshal(t *testing.T) { testCases := []struct { input string expected interface{} }{ { input: `"foo"`, expected: "foo", }, { input: `5`, expected: 5, }, { input: `["foo", "bar"]`, expected: []string{"foo", "bar"}, }, { input: `("foo", "bar")`, expected: []string{"foo", "bar"}, }, { input: `("foo",5)`, expected: []interface{}{"foo", 5}, }, { input: `{"foo": 5, "bar": 10}`, expected: map[string]int{"foo": 5, "bar": 10}, }, { input: `{"foo": ["qux"], "bar": []}`, expected: map[string][]string{"foo": {"qux"}, "bar": nil}, }, { input: `struct(Foo="foo", Bar=5)`, expected: struct { Foo string Bar int }{Foo: "foo", Bar: 5}, }, { // Unexported fields version of the above input: `struct(foo="foo", bar=5)`, expected: struct { foo string bar int }{foo: "foo", bar: 5}, }, { input: `{"foo": "foo2", "bar": ["bar2"], "baz": 5, "qux": {"qux2": "qux3"}, "quux": {"quux2": "quux3", "quux4": 5}}`, expected: map[string]interface{}{ "foo": "foo2", "bar": []string{"bar2"}, "baz": 5, "qux": map[string]string{"qux2": "qux3"}, "quux": map[string]interface{}{ "quux2": "quux3", "quux4": 5, }, }, }, } for _, tc := range testCases { x, err := UnmarshalReflect(createStarlarkValue(t, tc.input), reflect.TypeOf(tc.expected)) if err != nil { t.Error(err) continue } if !reflect.DeepEqual(x.Interface(), tc.expected) { t.Errorf(`Expected %#v, got %#v`, tc.expected, x.Interface()) } } }