2015-01-23 23:15:10 +01:00
|
|
|
// Copyright 2014 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.
|
|
|
|
|
2020-01-02 18:37:49 +01:00
|
|
|
package proptools
|
2014-05-28 01:34:41 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
2015-06-22 22:38:45 +02:00
|
|
|
|
|
|
|
"github.com/google/blueprint/parser"
|
2014-05-28 01:34:41 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var validUnpackTestCases = []struct {
|
2020-01-24 07:33:21 +01:00
|
|
|
name string
|
2014-05-28 01:34:41 +02:00
|
|
|
input string
|
2016-06-07 21:28:16 +02:00
|
|
|
output []interface{}
|
2016-08-06 02:19:36 +02:00
|
|
|
empty []interface{}
|
2015-06-22 22:38:45 +02:00
|
|
|
errs []error
|
2014-05-28 01:34:41 +02:00
|
|
|
}{
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "blank and unset",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
blank: "",
|
|
|
|
}
|
2015-10-30 23:53:55 +01:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S *string
|
2016-06-07 21:28:16 +02:00
|
|
|
Blank *string
|
|
|
|
Unset *string
|
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: StringPtr("abc"),
|
|
|
|
Blank: StringPtr(""),
|
2016-06-07 21:28:16 +02:00
|
|
|
Unset: nil,
|
|
|
|
},
|
2015-10-30 23:53:55 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "string",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
}
|
2014-05-28 01:34:41 +02:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2016-06-07 21:28:16 +02:00
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "abc",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
2014-05-28 01:34:41 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "bool",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
isGood: true,
|
|
|
|
}
|
2014-05-28 01:34:41 +02:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-06-07 21:28:16 +02:00
|
|
|
IsGood bool
|
|
|
|
}{
|
|
|
|
IsGood: true,
|
|
|
|
},
|
2014-05-28 01:34:41 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "boolptr",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
isGood: true,
|
|
|
|
isBad: false,
|
|
|
|
}
|
2015-10-30 23:53:55 +01:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-06-07 21:28:16 +02:00
|
|
|
IsGood *bool
|
|
|
|
IsBad *bool
|
|
|
|
IsUgly *bool
|
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
IsGood: BoolPtr(true),
|
|
|
|
IsBad: BoolPtr(false),
|
2016-06-07 21:28:16 +02:00
|
|
|
IsUgly: nil,
|
|
|
|
},
|
2015-10-30 23:53:55 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "slice",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
stuff: ["asdf", "jkl;", "qwert",
|
|
|
|
"uiop", "bnm,"],
|
|
|
|
empty: []
|
|
|
|
}
|
2014-05-28 01:34:41 +02:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2018-10-03 06:57:47 +02:00
|
|
|
Stuff []string
|
|
|
|
Empty []string
|
|
|
|
Nil []string
|
|
|
|
NonString []struct{ S string } `blueprint:"mutated"`
|
2016-06-07 21:28:16 +02:00
|
|
|
}{
|
2018-10-03 06:57:47 +02:00
|
|
|
Stuff: []string{"asdf", "jkl;", "qwert", "uiop", "bnm,"},
|
|
|
|
Empty: []string{},
|
|
|
|
Nil: nil,
|
|
|
|
NonString: nil,
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
2014-05-28 01:34:41 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "double nested",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
|
|
|
nested: {
|
|
|
|
s: "abc",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Nested struct {
|
|
|
|
Nested struct {
|
|
|
|
S string
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}{
|
|
|
|
Nested: struct{ Nested struct{ S string } }{
|
|
|
|
Nested: struct{ S string }{
|
|
|
|
S: "abc",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
name: "nested",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
}
|
2014-09-30 20:38:25 +02:00
|
|
|
}
|
2014-05-28 01:34:41 +02:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2016-06-07 21:28:16 +02:00
|
|
|
}
|
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
Nested: struct{ S string }{
|
|
|
|
S: "abc",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
2014-05-28 01:34:41 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "nested interface",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "def",
|
2016-08-06 02:19:36 +02:00
|
|
|
}
|
2014-09-30 20:38:25 +02:00
|
|
|
}
|
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested interface{}
|
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
Nested: &struct{ S string }{
|
|
|
|
S: "def",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
2014-09-30 20:38:25 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "mixed",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
|
|
|
foo: "abc",
|
|
|
|
},
|
|
|
|
bar: false,
|
|
|
|
baz: ["def", "ghi"],
|
|
|
|
}
|
2014-05-28 01:34:41 +02:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested struct {
|
|
|
|
Foo string
|
|
|
|
}
|
|
|
|
Bar bool
|
|
|
|
Baz []string
|
|
|
|
}{
|
|
|
|
Nested: struct{ Foo string }{
|
|
|
|
Foo: "abc",
|
|
|
|
},
|
|
|
|
Bar: false,
|
|
|
|
Baz: []string{"def", "ghi"},
|
2014-05-28 01:34:41 +02:00
|
|
|
},
|
|
|
|
},
|
2015-06-22 22:38:45 +02:00
|
|
|
},
|
|
|
|
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "filter",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
|
|
|
foo: "abc",
|
|
|
|
},
|
|
|
|
bar: false,
|
|
|
|
baz: ["def", "ghi"],
|
|
|
|
}
|
2015-06-22 22:38:45 +02:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested struct {
|
|
|
|
Foo string `allowNested:"true"`
|
|
|
|
} `blueprint:"filter(allowNested:\"true\")"`
|
|
|
|
Bar bool
|
|
|
|
Baz []string
|
2015-06-22 22:38:45 +02:00
|
|
|
}{
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested: struct {
|
|
|
|
Foo string `allowNested:"true"`
|
|
|
|
}{
|
|
|
|
Foo: "abc",
|
|
|
|
},
|
|
|
|
Bar: false,
|
|
|
|
Baz: []string{"def", "ghi"},
|
2015-06-22 22:38:45 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
Implement list of maps
Allow property value to be a list of maps, e.g.
my_module {
my_list: [
{ name: "foo", value: 42, something: true, },
{ name: "bar", value: 34, something: false, },
],
}
Test: internal
Change-Id: I2fc37d692aac39f23c9aa7bda2859ab49f3bc672
2020-02-12 07:39:47 +01:00
|
|
|
// List of maps
|
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "list of structs",
|
Implement list of maps
Allow property value to be a list of maps, e.g.
my_module {
my_list: [
{ name: "foo", value: 42, something: true, },
{ name: "bar", value: 34, something: false, },
],
}
Test: internal
Change-Id: I2fc37d692aac39f23c9aa7bda2859ab49f3bc672
2020-02-12 07:39:47 +01:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
mapslist: [
|
|
|
|
{
|
|
|
|
foo: "abc",
|
|
|
|
bar: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
foo: "def",
|
|
|
|
bar: false,
|
|
|
|
}
|
|
|
|
],
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Mapslist []struct {
|
|
|
|
Foo string
|
|
|
|
Bar bool
|
|
|
|
}
|
|
|
|
}{
|
|
|
|
Mapslist: []struct {
|
|
|
|
Foo string
|
|
|
|
Bar bool
|
|
|
|
}{
|
|
|
|
{Foo: "abc", Bar: true},
|
|
|
|
{Foo: "def", Bar: false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// List of pointers to structs
|
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "list of pointers to structs",
|
Implement list of maps
Allow property value to be a list of maps, e.g.
my_module {
my_list: [
{ name: "foo", value: 42, something: true, },
{ name: "bar", value: 34, something: false, },
],
}
Test: internal
Change-Id: I2fc37d692aac39f23c9aa7bda2859ab49f3bc672
2020-02-12 07:39:47 +01:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
mapslist: [
|
|
|
|
{
|
|
|
|
foo: "abc",
|
|
|
|
bar: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
foo: "def",
|
|
|
|
bar: false,
|
|
|
|
}
|
|
|
|
],
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Mapslist []*struct {
|
|
|
|
Foo string
|
|
|
|
Bar bool
|
|
|
|
}
|
|
|
|
}{
|
|
|
|
Mapslist: []*struct {
|
|
|
|
Foo string
|
|
|
|
Bar bool
|
|
|
|
}{
|
|
|
|
{Foo: "abc", Bar: true},
|
|
|
|
{Foo: "def", Bar: false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// List of lists
|
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "list of lists",
|
Implement list of maps
Allow property value to be a list of maps, e.g.
my_module {
my_list: [
{ name: "foo", value: 42, something: true, },
{ name: "bar", value: 34, something: false, },
],
}
Test: internal
Change-Id: I2fc37d692aac39f23c9aa7bda2859ab49f3bc672
2020-02-12 07:39:47 +01:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
listoflists: [
|
|
|
|
["abc",],
|
|
|
|
["def",],
|
|
|
|
],
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Listoflists [][]string
|
|
|
|
}{
|
|
|
|
Listoflists: [][]string{
|
|
|
|
[]string{"abc"},
|
|
|
|
[]string{"def"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// Multilevel
|
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "multilevel",
|
Implement list of maps
Allow property value to be a list of maps, e.g.
my_module {
my_list: [
{ name: "foo", value: 42, something: true, },
{ name: "bar", value: 34, something: false, },
],
}
Test: internal
Change-Id: I2fc37d692aac39f23c9aa7bda2859ab49f3bc672
2020-02-12 07:39:47 +01:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
name: "mymodule",
|
|
|
|
flag: true,
|
|
|
|
settings: ["foo1", "foo2", "foo3",],
|
|
|
|
perarch: {
|
|
|
|
arm: "32",
|
|
|
|
arm64: "64",
|
|
|
|
},
|
|
|
|
configvars: [
|
|
|
|
{ var: "var1", values: ["1.1", "1.2", ], },
|
|
|
|
{ var: "var2", values: ["2.1", ], },
|
|
|
|
],
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Name string
|
|
|
|
Flag bool
|
|
|
|
Settings []string
|
|
|
|
Perarch *struct {
|
|
|
|
Arm string
|
|
|
|
Arm64 string
|
|
|
|
}
|
|
|
|
Configvars []struct {
|
|
|
|
Var string
|
|
|
|
Values []string
|
|
|
|
}
|
|
|
|
}{
|
|
|
|
Name: "mymodule",
|
|
|
|
Flag: true,
|
|
|
|
Settings: []string{"foo1", "foo2", "foo3"},
|
|
|
|
Perarch: &struct {
|
|
|
|
Arm string
|
|
|
|
Arm64 string
|
|
|
|
}{Arm: "32", Arm64: "64"},
|
|
|
|
Configvars: []struct {
|
|
|
|
Var string
|
|
|
|
Values []string
|
|
|
|
}{
|
|
|
|
{Var: "var1", Values: []string{"1.1", "1.2"}},
|
|
|
|
{Var: "var2", Values: []string{"2.1"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-11-21 02:03:25 +01:00
|
|
|
// Anonymous struct
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "embedded struct",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
nested: {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "def",
|
2016-08-06 02:19:36 +02:00
|
|
|
},
|
|
|
|
}
|
2015-11-21 02:03:25 +01:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2015-11-21 02:03:25 +01:00
|
|
|
EmbeddedStruct
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested struct {
|
|
|
|
EmbeddedStruct
|
|
|
|
}
|
2015-11-21 02:03:25 +01:00
|
|
|
}{
|
|
|
|
EmbeddedStruct: EmbeddedStruct{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "abc",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
|
|
|
Nested: struct {
|
|
|
|
EmbeddedStruct
|
|
|
|
}{
|
|
|
|
EmbeddedStruct: EmbeddedStruct{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "def",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
2015-11-21 02:03:25 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// Anonymous interface
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "embedded interface",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
nested: {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "def",
|
2016-08-06 02:19:36 +02:00
|
|
|
},
|
|
|
|
}
|
2015-11-21 02:03:25 +01:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2015-11-21 02:03:25 +01:00
|
|
|
EmbeddedInterface
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested struct {
|
|
|
|
EmbeddedInterface
|
|
|
|
}
|
2015-11-21 02:03:25 +01:00
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
EmbeddedInterface: &struct{ S string }{
|
|
|
|
S: "abc",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
|
|
|
Nested: struct {
|
|
|
|
EmbeddedInterface
|
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
EmbeddedInterface: &struct{ S string }{
|
|
|
|
S: "def",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
2015-11-21 02:03:25 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// Anonymous struct with name collision
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "embedded name collision",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
nested: {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "def",
|
2016-08-06 02:19:36 +02:00
|
|
|
},
|
|
|
|
}
|
2015-11-21 02:03:25 +01:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2015-11-21 02:03:25 +01:00
|
|
|
EmbeddedStruct
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2016-06-07 21:28:16 +02:00
|
|
|
EmbeddedStruct
|
|
|
|
}
|
2015-11-21 02:03:25 +01:00
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "abc",
|
2015-11-21 02:03:25 +01:00
|
|
|
EmbeddedStruct: EmbeddedStruct{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "abc",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
|
|
|
Nested: struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2016-06-07 21:28:16 +02:00
|
|
|
EmbeddedStruct
|
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "def",
|
2016-06-07 21:28:16 +02:00
|
|
|
EmbeddedStruct: EmbeddedStruct{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "def",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
2015-11-21 02:03:25 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// Anonymous interface with name collision
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "embeded interface name collision",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
nested: {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "def",
|
2016-08-06 02:19:36 +02:00
|
|
|
},
|
|
|
|
}
|
2015-11-21 02:03:25 +01:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2015-11-21 02:03:25 +01:00
|
|
|
EmbeddedInterface
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2016-06-07 21:28:16 +02:00
|
|
|
EmbeddedInterface
|
|
|
|
}
|
2015-11-21 02:03:25 +01:00
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "abc",
|
|
|
|
EmbeddedInterface: &struct{ S string }{
|
|
|
|
S: "abc",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
|
|
|
Nested: struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2016-06-07 21:28:16 +02:00
|
|
|
EmbeddedInterface
|
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "def",
|
|
|
|
EmbeddedInterface: &struct{ S string }{
|
|
|
|
S: "def",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// Variables
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "variables",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
list = ["abc"]
|
|
|
|
string = "def"
|
|
|
|
list_with_variable = [string]
|
2020-03-04 02:36:00 +01:00
|
|
|
struct_value = { name: "foo" }
|
2016-08-06 02:19:36 +02:00
|
|
|
m {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: string,
|
2016-08-06 02:19:36 +02:00
|
|
|
list: list,
|
|
|
|
list2: list_with_variable,
|
2020-03-04 02:36:00 +01:00
|
|
|
structattr: struct_value,
|
2016-08-06 02:19:36 +02:00
|
|
|
}
|
2016-06-07 21:28:16 +02:00
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2020-03-04 02:36:00 +01:00
|
|
|
S string
|
|
|
|
List []string
|
|
|
|
List2 []string
|
|
|
|
Structattr struct {
|
|
|
|
Name string
|
|
|
|
}
|
2016-06-07 21:28:16 +02:00
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "def",
|
2016-06-07 21:28:16 +02:00
|
|
|
List: []string{"abc"},
|
|
|
|
List2: []string{"def"},
|
2020-03-04 02:36:00 +01:00
|
|
|
Structattr: struct {
|
|
|
|
Name string
|
|
|
|
}{
|
|
|
|
Name: "foo",
|
|
|
|
},
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// Multiple property structs
|
2016-08-06 02:19:36 +02:00
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "multiple",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
}
|
2016-06-07 21:28:16 +02:00
|
|
|
}
|
|
|
|
`,
|
2016-08-06 02:19:36 +02:00
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2016-06-07 21:28:16 +02:00
|
|
|
}
|
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
Nested: struct{ S string }{
|
|
|
|
S: "abc",
|
2016-06-07 21:28:16 +02:00
|
|
|
},
|
|
|
|
},
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-06-07 21:28:16 +02:00
|
|
|
Nested struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2016-06-07 21:28:16 +02:00
|
|
|
}
|
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
Nested: struct{ S string }{
|
|
|
|
S: "abc",
|
2015-11-21 02:03:25 +01:00
|
|
|
},
|
|
|
|
},
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-06-07 21:28:16 +02:00
|
|
|
}{},
|
2015-11-21 02:03:25 +01:00
|
|
|
},
|
2016-08-06 02:19:36 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// Nil pointer to struct
|
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "nil struct pointer",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-08-06 02:19:36 +02:00
|
|
|
Nested *struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2016-08-06 02:19:36 +02:00
|
|
|
}
|
|
|
|
}{
|
2020-01-02 18:37:49 +01:00
|
|
|
Nested: &struct{ S string }{
|
|
|
|
S: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
empty: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Nested *struct {
|
2020-01-02 18:37:49 +01:00
|
|
|
S string
|
2016-08-06 02:19:36 +02:00
|
|
|
}
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// Interface containing nil pointer to struct
|
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "interface nil struct pointer",
|
2016-08-06 02:19:36 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
2020-01-02 18:37:49 +01:00
|
|
|
s: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2016-08-06 02:19:36 +02:00
|
|
|
Nested interface{}
|
|
|
|
}{
|
|
|
|
Nested: &EmbeddedStruct{
|
2020-01-02 18:37:49 +01:00
|
|
|
S: "abc",
|
2016-08-06 02:19:36 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
empty: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Nested interface{}
|
|
|
|
}{
|
|
|
|
Nested: (*EmbeddedStruct)(nil),
|
|
|
|
},
|
|
|
|
},
|
2015-11-21 02:03:25 +01:00
|
|
|
},
|
2017-07-29 02:51:37 +02:00
|
|
|
|
|
|
|
// Factory set properties
|
|
|
|
{
|
2020-01-24 07:33:21 +01:00
|
|
|
name: "factory properties",
|
2017-07-29 02:51:37 +02:00
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
string: "abc",
|
|
|
|
string_ptr: "abc",
|
|
|
|
bool: false,
|
|
|
|
bool_ptr: false,
|
|
|
|
list: ["a", "b", "c"],
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
2020-01-28 01:14:31 +01:00
|
|
|
&struct {
|
2017-07-29 02:51:37 +02:00
|
|
|
String string
|
|
|
|
String_ptr *string
|
|
|
|
Bool bool
|
|
|
|
Bool_ptr *bool
|
|
|
|
List []string
|
|
|
|
}{
|
|
|
|
String: "012abc",
|
2020-01-02 18:37:49 +01:00
|
|
|
String_ptr: StringPtr("abc"),
|
2017-07-29 02:51:37 +02:00
|
|
|
Bool: true,
|
2020-01-02 18:37:49 +01:00
|
|
|
Bool_ptr: BoolPtr(false),
|
2017-07-29 02:51:37 +02:00
|
|
|
List: []string{"0", "1", "2", "a", "b", "c"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
empty: []interface{}{
|
|
|
|
&struct {
|
|
|
|
String string
|
|
|
|
String_ptr *string
|
|
|
|
Bool bool
|
|
|
|
Bool_ptr *bool
|
|
|
|
List []string
|
|
|
|
}{
|
|
|
|
String: "012",
|
2020-01-02 18:37:49 +01:00
|
|
|
String_ptr: StringPtr("012"),
|
2017-07-29 02:51:37 +02:00
|
|
|
Bool: true,
|
2020-01-02 18:37:49 +01:00
|
|
|
Bool_ptr: BoolPtr(true),
|
2017-07-29 02:51:37 +02:00
|
|
|
List: []string{"0", "1", "2"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-02-05 22:45:11 +01:00
|
|
|
// Captitalized property
|
|
|
|
{
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
CAPITALIZED: "foo",
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
CAPITALIZED string
|
|
|
|
}{
|
|
|
|
CAPITALIZED: "foo",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
Select statements
Select statements are a new blueprint feature inspired by bazel's select
statements. They are essentially alternative syntax for soong config
variables that require less boilerplate. In addition, they support
making decisions based on a module's variant, which will eliminate
the need for manual property struct manipulation, such as the arch
mutator's arch: and target: properties.
In order to support decisions based on the variant, select statements
cannot be evaluated as soon as they're parsed. Instead, they must be
stored in the property struct unevaluated. This means that individual
properties need to change their type from say, string, to
Configurable[string]. Currently, only configurable strings, bools, and
string slices are supported, but more types can be added later.
The module implementation must call my_property.Evaluate(ctx) in order
to get the final, resolved value of the select statement.
Bug: 323382414
Test: go tests
Change-Id: I62f8721d7f0ac3d1df4a06d7eaa260a5aa7fcba3
2024-02-02 02:44:27 +01:00
|
|
|
{
|
|
|
|
name: "String configurable property that isn't configured",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
foo: "bar"
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Foo Configurable[string]
|
|
|
|
}{
|
|
|
|
Foo: Configurable[string]{
|
|
|
|
propertyName: "foo",
|
2024-04-27 01:39:54 +02:00
|
|
|
inner: &configurableInner[string]{
|
|
|
|
single: singleConfigurable[string]{
|
|
|
|
cases: []ConfigurableCase[string]{{
|
|
|
|
value: StringPtr("bar"),
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
},
|
Select statements
Select statements are a new blueprint feature inspired by bazel's select
statements. They are essentially alternative syntax for soong config
variables that require less boilerplate. In addition, they support
making decisions based on a module's variant, which will eliminate
the need for manual property struct manipulation, such as the arch
mutator's arch: and target: properties.
In order to support decisions based on the variant, select statements
cannot be evaluated as soon as they're parsed. Instead, they must be
stored in the property struct unevaluated. This means that individual
properties need to change their type from say, string, to
Configurable[string]. Currently, only configurable strings, bools, and
string slices are supported, but more types can be added later.
The module implementation must call my_property.Evaluate(ctx) in order
to get the final, resolved value of the select statement.
Bug: 323382414
Test: go tests
Change-Id: I62f8721d7f0ac3d1df4a06d7eaa260a5aa7fcba3
2024-02-02 02:44:27 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Bool configurable property that isn't configured",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
foo: true,
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Foo Configurable[bool]
|
|
|
|
}{
|
|
|
|
Foo: Configurable[bool]{
|
|
|
|
propertyName: "foo",
|
2024-04-27 01:39:54 +02:00
|
|
|
inner: &configurableInner[bool]{
|
|
|
|
single: singleConfigurable[bool]{
|
|
|
|
cases: []ConfigurableCase[bool]{{
|
|
|
|
value: BoolPtr(true),
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
},
|
Select statements
Select statements are a new blueprint feature inspired by bazel's select
statements. They are essentially alternative syntax for soong config
variables that require less boilerplate. In addition, they support
making decisions based on a module's variant, which will eliminate
the need for manual property struct manipulation, such as the arch
mutator's arch: and target: properties.
In order to support decisions based on the variant, select statements
cannot be evaluated as soon as they're parsed. Instead, they must be
stored in the property struct unevaluated. This means that individual
properties need to change their type from say, string, to
Configurable[string]. Currently, only configurable strings, bools, and
string slices are supported, but more types can be added later.
The module implementation must call my_property.Evaluate(ctx) in order
to get the final, resolved value of the select statement.
Bug: 323382414
Test: go tests
Change-Id: I62f8721d7f0ac3d1df4a06d7eaa260a5aa7fcba3
2024-02-02 02:44:27 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "String list configurable property that isn't configured",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
foo: ["a", "b"],
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Foo Configurable[[]string]
|
|
|
|
}{
|
|
|
|
Foo: Configurable[[]string]{
|
|
|
|
propertyName: "foo",
|
2024-04-27 01:39:54 +02:00
|
|
|
inner: &configurableInner[[]string]{
|
|
|
|
single: singleConfigurable[[]string]{
|
|
|
|
cases: []ConfigurableCase[[]string]{{
|
|
|
|
value: &[]string{"a", "b"},
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
},
|
Select statements
Select statements are a new blueprint feature inspired by bazel's select
statements. They are essentially alternative syntax for soong config
variables that require less boilerplate. In addition, they support
making decisions based on a module's variant, which will eliminate
the need for manual property struct manipulation, such as the arch
mutator's arch: and target: properties.
In order to support decisions based on the variant, select statements
cannot be evaluated as soon as they're parsed. Instead, they must be
stored in the property struct unevaluated. This means that individual
properties need to change their type from say, string, to
Configurable[string]. Currently, only configurable strings, bools, and
string slices are supported, but more types can be added later.
The module implementation must call my_property.Evaluate(ctx) in order
to get the final, resolved value of the select statement.
Bug: 323382414
Test: go tests
Change-Id: I62f8721d7f0ac3d1df4a06d7eaa260a5aa7fcba3
2024-02-02 02:44:27 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Configurable property",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
foo: select(soong_config_variable("my_namespace", "my_variable"), {
|
|
|
|
"a": "a2",
|
|
|
|
"b": "b2",
|
2024-04-03 01:42:58 +02:00
|
|
|
default: "c2",
|
Select statements
Select statements are a new blueprint feature inspired by bazel's select
statements. They are essentially alternative syntax for soong config
variables that require less boilerplate. In addition, they support
making decisions based on a module's variant, which will eliminate
the need for manual property struct manipulation, such as the arch
mutator's arch: and target: properties.
In order to support decisions based on the variant, select statements
cannot be evaluated as soon as they're parsed. Instead, they must be
stored in the property struct unevaluated. This means that individual
properties need to change their type from say, string, to
Configurable[string]. Currently, only configurable strings, bools, and
string slices are supported, but more types can be added later.
The module implementation must call my_property.Evaluate(ctx) in order
to get the final, resolved value of the select statement.
Bug: 323382414
Test: go tests
Change-Id: I62f8721d7f0ac3d1df4a06d7eaa260a5aa7fcba3
2024-02-02 02:44:27 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Foo Configurable[string]
|
|
|
|
}{
|
|
|
|
Foo: Configurable[string]{
|
|
|
|
propertyName: "foo",
|
2024-04-27 01:39:54 +02:00
|
|
|
inner: &configurableInner[string]{
|
|
|
|
single: singleConfigurable[string]{
|
|
|
|
conditions: []ConfigurableCondition{{
|
|
|
|
functionName: "soong_config_variable",
|
|
|
|
args: []string{
|
|
|
|
"my_namespace",
|
|
|
|
"my_variable",
|
|
|
|
},
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
}},
|
2024-04-27 01:39:54 +02:00
|
|
|
cases: []ConfigurableCase[string]{
|
|
|
|
{
|
|
|
|
patterns: []ConfigurablePattern{{
|
|
|
|
typ: configurablePatternTypeString,
|
|
|
|
stringValue: "a",
|
|
|
|
}},
|
|
|
|
value: StringPtr("a2"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
patterns: []ConfigurablePattern{{
|
|
|
|
typ: configurablePatternTypeString,
|
|
|
|
stringValue: "b",
|
|
|
|
}},
|
|
|
|
value: StringPtr("b2"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
patterns: []ConfigurablePattern{{
|
|
|
|
typ: configurablePatternTypeDefault,
|
|
|
|
}},
|
|
|
|
value: StringPtr("c2"),
|
|
|
|
},
|
|
|
|
},
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
},
|
Select statements
Select statements are a new blueprint feature inspired by bazel's select
statements. They are essentially alternative syntax for soong config
variables that require less boilerplate. In addition, they support
making decisions based on a module's variant, which will eliminate
the need for manual property struct manipulation, such as the arch
mutator's arch: and target: properties.
In order to support decisions based on the variant, select statements
cannot be evaluated as soon as they're parsed. Instead, they must be
stored in the property struct unevaluated. This means that individual
properties need to change their type from say, string, to
Configurable[string]. Currently, only configurable strings, bools, and
string slices are supported, but more types can be added later.
The module implementation must call my_property.Evaluate(ctx) in order
to get the final, resolved value of the select statement.
Bug: 323382414
Test: go tests
Change-Id: I62f8721d7f0ac3d1df4a06d7eaa260a5aa7fcba3
2024-02-02 02:44:27 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Configurable property appending",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
foo: select(soong_config_variable("my_namespace", "my_variable"), {
|
|
|
|
"a": "a2",
|
|
|
|
"b": "b2",
|
2024-04-03 01:42:58 +02:00
|
|
|
default: "c2",
|
Select statements
Select statements are a new blueprint feature inspired by bazel's select
statements. They are essentially alternative syntax for soong config
variables that require less boilerplate. In addition, they support
making decisions based on a module's variant, which will eliminate
the need for manual property struct manipulation, such as the arch
mutator's arch: and target: properties.
In order to support decisions based on the variant, select statements
cannot be evaluated as soon as they're parsed. Instead, they must be
stored in the property struct unevaluated. This means that individual
properties need to change their type from say, string, to
Configurable[string]. Currently, only configurable strings, bools, and
string slices are supported, but more types can be added later.
The module implementation must call my_property.Evaluate(ctx) in order
to get the final, resolved value of the select statement.
Bug: 323382414
Test: go tests
Change-Id: I62f8721d7f0ac3d1df4a06d7eaa260a5aa7fcba3
2024-02-02 02:44:27 +01:00
|
|
|
}) + select(soong_config_variable("my_namespace", "my_2nd_variable"), {
|
|
|
|
"d": "d2",
|
|
|
|
"e": "e2",
|
2024-04-03 01:42:58 +02:00
|
|
|
default: "f2",
|
Select statements
Select statements are a new blueprint feature inspired by bazel's select
statements. They are essentially alternative syntax for soong config
variables that require less boilerplate. In addition, they support
making decisions based on a module's variant, which will eliminate
the need for manual property struct manipulation, such as the arch
mutator's arch: and target: properties.
In order to support decisions based on the variant, select statements
cannot be evaluated as soon as they're parsed. Instead, they must be
stored in the property struct unevaluated. This means that individual
properties need to change their type from say, string, to
Configurable[string]. Currently, only configurable strings, bools, and
string slices are supported, but more types can be added later.
The module implementation must call my_property.Evaluate(ctx) in order
to get the final, resolved value of the select statement.
Bug: 323382414
Test: go tests
Change-Id: I62f8721d7f0ac3d1df4a06d7eaa260a5aa7fcba3
2024-02-02 02:44:27 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Foo Configurable[string]
|
|
|
|
}{
|
|
|
|
Foo: Configurable[string]{
|
|
|
|
propertyName: "foo",
|
2024-04-27 01:39:54 +02:00
|
|
|
inner: &configurableInner[string]{
|
|
|
|
single: singleConfigurable[string]{
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
conditions: []ConfigurableCondition{{
|
2024-04-27 01:39:54 +02:00
|
|
|
functionName: "soong_config_variable",
|
|
|
|
args: []string{
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
"my_namespace",
|
2024-04-27 01:39:54 +02:00
|
|
|
"my_variable",
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
},
|
|
|
|
}},
|
2024-04-23 22:50:40 +02:00
|
|
|
cases: []ConfigurableCase[string]{
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
{
|
2024-04-23 22:50:40 +02:00
|
|
|
patterns: []ConfigurablePattern{{
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
typ: configurablePatternTypeString,
|
2024-04-27 01:39:54 +02:00
|
|
|
stringValue: "a",
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
}},
|
2024-04-27 01:39:54 +02:00
|
|
|
value: StringPtr("a2"),
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
},
|
|
|
|
{
|
2024-04-23 22:50:40 +02:00
|
|
|
patterns: []ConfigurablePattern{{
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
typ: configurablePatternTypeString,
|
2024-04-27 01:39:54 +02:00
|
|
|
stringValue: "b",
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
}},
|
2024-04-27 01:39:54 +02:00
|
|
|
value: StringPtr("b2"),
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
},
|
|
|
|
{
|
2024-04-23 22:50:40 +02:00
|
|
|
patterns: []ConfigurablePattern{{
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
typ: configurablePatternTypeDefault,
|
|
|
|
}},
|
2024-04-27 01:39:54 +02:00
|
|
|
value: StringPtr("c2"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
next: &configurableInner[string]{
|
|
|
|
single: singleConfigurable[string]{
|
|
|
|
conditions: []ConfigurableCondition{{
|
|
|
|
functionName: "soong_config_variable",
|
|
|
|
args: []string{
|
|
|
|
"my_namespace",
|
|
|
|
"my_2nd_variable",
|
|
|
|
},
|
|
|
|
}},
|
|
|
|
cases: []ConfigurableCase[string]{
|
|
|
|
{
|
|
|
|
patterns: []ConfigurablePattern{{
|
|
|
|
typ: configurablePatternTypeString,
|
|
|
|
stringValue: "d",
|
|
|
|
}},
|
|
|
|
value: StringPtr("d2"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
patterns: []ConfigurablePattern{{
|
|
|
|
typ: configurablePatternTypeString,
|
|
|
|
stringValue: "e",
|
|
|
|
}},
|
|
|
|
value: StringPtr("e2"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
patterns: []ConfigurablePattern{{
|
|
|
|
typ: configurablePatternTypeDefault,
|
|
|
|
}},
|
|
|
|
value: StringPtr("f2"),
|
|
|
|
},
|
Support multi-variable selects and typed selects
This adds support for selecting on multiple variables at once, so that
you can do AND/OR combindations of them. For example:
select((
arch(),
os(),
), {
("arm64", "linux"): ["libfoo64"],
(default, "linux"): ["libfoo"],
(default, "windows"): ["libfoowindows"],
(default, default): ["libbar"],
})
It also allows for select conditions to be boolean-typed. You can
write literal true and false without quotes to select on them. Currently
we don't have any boolean-typed variables though, so a fake one was
added for testing.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: Ibe586e7b21865b8734027848cc421594cbd1d8cc
2024-04-10 23:57:34 +02:00
|
|
|
},
|
Select statements
Select statements are a new blueprint feature inspired by bazel's select
statements. They are essentially alternative syntax for soong config
variables that require less boilerplate. In addition, they support
making decisions based on a module's variant, which will eliminate
the need for manual property struct manipulation, such as the arch
mutator's arch: and target: properties.
In order to support decisions based on the variant, select statements
cannot be evaluated as soon as they're parsed. Instead, they must be
stored in the property struct unevaluated. This means that individual
properties need to change their type from say, string, to
Configurable[string]. Currently, only configurable strings, bools, and
string slices are supported, but more types can be added later.
The module implementation must call my_property.Evaluate(ctx) in order
to get the final, resolved value of the select statement.
Bug: 323382414
Test: go tests
Change-Id: I62f8721d7f0ac3d1df4a06d7eaa260a5aa7fcba3
2024-02-02 02:44:27 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2024-04-12 23:43:10 +02:00
|
|
|
{
|
|
|
|
name: "Unpack variable to configurable property",
|
|
|
|
input: `
|
|
|
|
my_string_variable = "asdf"
|
|
|
|
my_bool_variable = true
|
|
|
|
m {
|
|
|
|
foo: my_string_variable,
|
|
|
|
bar: my_bool_variable,
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Foo Configurable[string]
|
|
|
|
Bar Configurable[bool]
|
|
|
|
}{
|
|
|
|
Foo: Configurable[string]{
|
|
|
|
propertyName: "foo",
|
2024-04-27 01:39:54 +02:00
|
|
|
inner: &configurableInner[string]{
|
|
|
|
single: singleConfigurable[string]{
|
|
|
|
cases: []ConfigurableCase[string]{{
|
|
|
|
value: StringPtr("asdf"),
|
|
|
|
}},
|
2024-04-12 23:43:10 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Bar: Configurable[bool]{
|
|
|
|
propertyName: "bar",
|
2024-04-27 01:39:54 +02:00
|
|
|
inner: &configurableInner[bool]{
|
|
|
|
single: singleConfigurable[bool]{
|
|
|
|
cases: []ConfigurableCase[bool]{{
|
|
|
|
value: BoolPtr(true),
|
|
|
|
}},
|
2024-04-12 23:43:10 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2014-05-28 01:34:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestUnpackProperties(t *testing.T) {
|
|
|
|
for _, testCase := range validUnpackTestCases {
|
2020-01-24 07:33:21 +01:00
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
|
|
r := bytes.NewBufferString(testCase.input)
|
|
|
|
file, errs := parser.ParseAndEval("", r, parser.NewScope(nil))
|
|
|
|
if len(errs) != 0 {
|
|
|
|
t.Errorf("test case: %s", testCase.input)
|
|
|
|
t.Errorf("unexpected parse errors:")
|
|
|
|
for _, err := range errs {
|
|
|
|
t.Errorf(" %s", err)
|
|
|
|
}
|
|
|
|
t.FailNow()
|
2014-05-28 01:34:41 +02:00
|
|
|
}
|
|
|
|
|
2020-01-24 07:33:21 +01:00
|
|
|
for _, def := range file.Defs {
|
|
|
|
module, ok := def.(*parser.Module)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
2014-05-28 01:34:41 +02:00
|
|
|
|
2020-01-24 07:33:21 +01:00
|
|
|
var output []interface{}
|
|
|
|
if len(testCase.empty) > 0 {
|
|
|
|
for _, p := range testCase.empty {
|
|
|
|
output = append(output, CloneProperties(reflect.ValueOf(p)).Interface())
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for _, p := range testCase.output {
|
|
|
|
output = append(output, CloneEmptyProperties(reflect.ValueOf(p)).Interface())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-02 16:51:08 +02:00
|
|
|
_, errs = UnpackProperties(module.Properties, output...)
|
2020-01-24 07:33:21 +01:00
|
|
|
if len(errs) != 0 && len(testCase.errs) == 0 {
|
|
|
|
t.Errorf("test case: %s", testCase.input)
|
|
|
|
t.Errorf("unexpected unpack errors:")
|
|
|
|
for _, err := range errs {
|
|
|
|
t.Errorf(" %s", err)
|
|
|
|
}
|
|
|
|
t.FailNow()
|
|
|
|
} else if !reflect.DeepEqual(errs, testCase.errs) {
|
|
|
|
t.Errorf("test case: %s", testCase.input)
|
|
|
|
t.Errorf("incorrect errors:")
|
|
|
|
t.Errorf(" expected: %+v", testCase.errs)
|
|
|
|
t.Errorf(" got: %+v", errs)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(output) != len(testCase.output) {
|
|
|
|
t.Fatalf("incorrect number of property structs, expected %d got %d",
|
|
|
|
len(testCase.output), len(output))
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range output {
|
|
|
|
got := reflect.ValueOf(output[i]).Interface()
|
|
|
|
if !reflect.DeepEqual(got, testCase.output[i]) {
|
|
|
|
t.Errorf("test case: %s", testCase.input)
|
|
|
|
t.Errorf("incorrect output:")
|
|
|
|
t.Errorf(" expected: %+v", testCase.output[i])
|
|
|
|
t.Errorf(" got: %+v", got)
|
|
|
|
}
|
2016-08-06 02:19:36 +02:00
|
|
|
}
|
2016-06-07 21:28:16 +02:00
|
|
|
}
|
2020-01-24 07:33:21 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUnpackErrors(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
input string
|
|
|
|
output []interface{}
|
|
|
|
errors []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "missing",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
missing: true,
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{},
|
|
|
|
errors: []string{`<input>:3:13: unrecognized property "missing"`},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "missing nested",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
|
|
|
missing: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Nested struct{}
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
errors: []string{`<input>:4:14: unrecognized property "nested.missing"`},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "mutated",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
mutated: true,
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Mutated bool `blueprint:"mutated"`
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
errors: []string{`<input>:3:13: mutated field mutated cannot be set in a Blueprint file`},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "nested mutated",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
|
|
|
mutated: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Nested struct {
|
|
|
|
Mutated bool `blueprint:"mutated"`
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
errors: []string{`<input>:4:14: mutated field nested.mutated cannot be set in a Blueprint file`},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "duplicate",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
exists: true,
|
|
|
|
exists: true,
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Exists bool
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
errors: []string{
|
|
|
|
`<input>:4:12: property "exists" already defined`,
|
|
|
|
`<input>:3:12: <-- previous definition here`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "nested duplicate",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
nested: {
|
|
|
|
exists: true,
|
|
|
|
exists: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Nested struct {
|
|
|
|
Exists bool
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
errors: []string{
|
|
|
|
`<input>:5:13: property "nested.exists" already defined`,
|
|
|
|
`<input>:4:13: <-- previous definition here`,
|
|
|
|
},
|
|
|
|
},
|
2021-01-16 05:09:51 +01:00
|
|
|
{
|
|
|
|
name: "wrong type",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
int: "foo",
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Int *int64
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
errors: []string{
|
|
|
|
`<input>:3:11: can't assign string value to int64 property "int"`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "wrong type for map",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
map: "foo",
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Map struct {
|
|
|
|
S string
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
errors: []string{
|
|
|
|
`<input>:3:11: can't assign string value to map property "map"`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "wrong type for list",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
list: "foo",
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
List []string
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
errors: []string{
|
|
|
|
`<input>:3:12: can't assign string value to list property "list"`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "wrong type for list of maps",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
map_list: "foo",
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Map_list []struct {
|
|
|
|
S string
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
errors: []string{
|
|
|
|
`<input>:3:16: can't assign string value to list property "map_list"`,
|
|
|
|
},
|
|
|
|
},
|
2023-10-30 22:48:37 +01:00
|
|
|
{
|
|
|
|
name: "non-existent property",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
foo: {
|
|
|
|
foo_prop1: true,
|
|
|
|
foo_prop2: false,
|
|
|
|
foo_prop3: true,
|
|
|
|
},
|
|
|
|
bar: {
|
|
|
|
bar_prop: false,
|
|
|
|
},
|
|
|
|
baz: true,
|
|
|
|
exist: false,
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Foo struct {
|
|
|
|
Foo_prop1 bool
|
|
|
|
}
|
|
|
|
Exist bool
|
|
|
|
}{},
|
|
|
|
},
|
|
|
|
errors: []string{
|
|
|
|
`<input>:5:16: unrecognized property "foo.foo_prop2"`,
|
|
|
|
`<input>:6:16: unrecognized property "foo.foo_prop3"`,
|
|
|
|
`<input>:9:15: unrecognized property "bar.bar_prop"`,
|
|
|
|
`<input>:11:9: unrecognized property "baz"`,
|
|
|
|
},
|
|
|
|
},
|
2020-01-24 07:33:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, testCase := range testCases {
|
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
|
|
r := bytes.NewBufferString(testCase.input)
|
|
|
|
file, errs := parser.ParseAndEval("", r, parser.NewScope(nil))
|
|
|
|
if len(errs) != 0 {
|
2016-06-07 21:28:16 +02:00
|
|
|
t.Errorf("test case: %s", testCase.input)
|
2020-01-24 07:33:21 +01:00
|
|
|
t.Errorf("unexpected parse errors:")
|
2016-06-07 21:28:16 +02:00
|
|
|
for _, err := range errs {
|
|
|
|
t.Errorf(" %s", err)
|
|
|
|
}
|
|
|
|
t.FailNow()
|
|
|
|
}
|
|
|
|
|
2020-01-24 07:33:21 +01:00
|
|
|
for _, def := range file.Defs {
|
|
|
|
module, ok := def.(*parser.Module)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
2016-06-07 21:28:16 +02:00
|
|
|
|
2020-01-24 07:33:21 +01:00
|
|
|
var output []interface{}
|
|
|
|
for _, p := range testCase.output {
|
|
|
|
output = append(output, CloneEmptyProperties(reflect.ValueOf(p)).Interface())
|
|
|
|
}
|
|
|
|
|
|
|
|
_, errs = UnpackProperties(module.Properties, output...)
|
|
|
|
|
|
|
|
printErrors := false
|
|
|
|
for _, expectedErr := range testCase.errors {
|
|
|
|
foundError := false
|
|
|
|
for _, err := range errs {
|
|
|
|
if err.Error() == expectedErr {
|
|
|
|
foundError = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !foundError {
|
|
|
|
t.Errorf("expected error %s", expectedErr)
|
|
|
|
printErrors = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if printErrors {
|
|
|
|
t.Errorf("got errors:")
|
|
|
|
for _, err := range errs {
|
|
|
|
t.Errorf(" %s", err.Error())
|
|
|
|
}
|
2016-06-07 21:28:16 +02:00
|
|
|
}
|
|
|
|
}
|
2020-01-24 07:33:21 +01:00
|
|
|
})
|
2014-05-28 01:34:41 +02:00
|
|
|
}
|
|
|
|
}
|
2016-06-01 00:53:32 +02:00
|
|
|
|
Implement list of maps
Allow property value to be a list of maps, e.g.
my_module {
my_list: [
{ name: "foo", value: 42, something: true, },
{ name: "bar", value: 34, something: false, },
],
}
Test: internal
Change-Id: I2fc37d692aac39f23c9aa7bda2859ab49f3bc672
2020-02-12 07:39:47 +01:00
|
|
|
func BenchmarkUnpackProperties(b *testing.B) {
|
|
|
|
run := func(b *testing.B, props []interface{}, input string) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.StopTimer()
|
|
|
|
r := bytes.NewBufferString(input)
|
|
|
|
file, errs := parser.ParseAndEval("", r, parser.NewScope(nil))
|
|
|
|
if len(errs) != 0 {
|
|
|
|
b.Errorf("test case: %s", input)
|
|
|
|
b.Errorf("unexpected parse errors:")
|
|
|
|
for _, err := range errs {
|
|
|
|
b.Errorf(" %s", err)
|
|
|
|
}
|
|
|
|
b.FailNow()
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
for _, def := range file.Defs {
|
|
|
|
module, ok := def.(*parser.Module)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
var output []interface{}
|
|
|
|
for _, p := range props {
|
|
|
|
output = append(output, CloneProperties(reflect.ValueOf(p)).Interface())
|
|
|
|
}
|
|
|
|
|
|
|
|
b.StartTimer()
|
|
|
|
_, errs = UnpackProperties(module.Properties, output...)
|
|
|
|
b.StopTimer()
|
|
|
|
if len(errs) > 0 {
|
|
|
|
b.Errorf("unexpected unpack errors:")
|
|
|
|
for _, err := range errs {
|
|
|
|
b.Errorf(" %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-06-01 00:53:32 +02:00
|
|
|
}
|
Implement list of maps
Allow property value to be a list of maps, e.g.
my_module {
my_list: [
{ name: "foo", value: 42, something: true, },
{ name: "bar", value: 34, something: false, },
],
}
Test: internal
Change-Id: I2fc37d692aac39f23c9aa7bda2859ab49f3bc672
2020-02-12 07:39:47 +01:00
|
|
|
|
|
|
|
b.Run("basic", func(b *testing.B) {
|
|
|
|
props := []interface{}{
|
|
|
|
&struct {
|
|
|
|
Nested struct {
|
|
|
|
S string
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
}
|
|
|
|
bp := `
|
|
|
|
m {
|
|
|
|
nested: {
|
|
|
|
s: "abc",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
`
|
|
|
|
run(b, props, bp)
|
|
|
|
})
|
|
|
|
|
|
|
|
b.Run("interface", func(b *testing.B) {
|
|
|
|
props := []interface{}{
|
|
|
|
&struct {
|
|
|
|
Nested interface{}
|
|
|
|
}{
|
|
|
|
Nested: (*struct {
|
|
|
|
S string
|
|
|
|
})(nil),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
bp := `
|
|
|
|
m {
|
|
|
|
nested: {
|
|
|
|
s: "abc",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
`
|
|
|
|
run(b, props, bp)
|
|
|
|
})
|
|
|
|
|
|
|
|
b.Run("many", func(b *testing.B) {
|
|
|
|
props := []interface{}{
|
|
|
|
&struct {
|
|
|
|
A *string
|
|
|
|
B *string
|
|
|
|
C *string
|
|
|
|
D *string
|
|
|
|
E *string
|
|
|
|
F *string
|
|
|
|
G *string
|
|
|
|
H *string
|
|
|
|
I *string
|
|
|
|
J *string
|
|
|
|
}{},
|
|
|
|
}
|
|
|
|
bp := `
|
|
|
|
m {
|
|
|
|
a: "a",
|
|
|
|
b: "b",
|
|
|
|
c: "c",
|
|
|
|
d: "d",
|
|
|
|
e: "e",
|
|
|
|
f: "f",
|
|
|
|
g: "g",
|
|
|
|
h: "h",
|
|
|
|
i: "i",
|
|
|
|
j: "j",
|
|
|
|
}
|
|
|
|
`
|
|
|
|
run(b, props, bp)
|
|
|
|
})
|
|
|
|
|
|
|
|
b.Run("deep", func(b *testing.B) {
|
|
|
|
props := []interface{}{
|
|
|
|
&struct {
|
|
|
|
Nested struct {
|
|
|
|
Nested struct {
|
|
|
|
Nested struct {
|
|
|
|
Nested struct {
|
|
|
|
Nested struct {
|
|
|
|
Nested struct {
|
|
|
|
Nested struct {
|
|
|
|
Nested struct {
|
|
|
|
Nested struct {
|
|
|
|
Nested struct {
|
|
|
|
S string
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
}
|
|
|
|
bp := `
|
|
|
|
m {
|
|
|
|
nested: { nested: { nested: { nested: { nested: {
|
|
|
|
nested: { nested: { nested: { nested: { nested: {
|
|
|
|
s: "abc",
|
|
|
|
}, }, }, }, },
|
|
|
|
}, }, }, }, },
|
|
|
|
}
|
|
|
|
`
|
|
|
|
run(b, props, bp)
|
|
|
|
})
|
|
|
|
|
|
|
|
b.Run("mix", func(b *testing.B) {
|
|
|
|
props := []interface{}{
|
|
|
|
&struct {
|
|
|
|
Name string
|
|
|
|
Flag bool
|
|
|
|
Settings []string
|
|
|
|
Perarch *struct {
|
|
|
|
Arm string
|
|
|
|
Arm64 string
|
|
|
|
}
|
|
|
|
Configvars []struct {
|
|
|
|
Name string
|
|
|
|
Values []string
|
|
|
|
}
|
|
|
|
}{},
|
|
|
|
}
|
|
|
|
bp := `
|
|
|
|
m {
|
|
|
|
name: "mymodule",
|
|
|
|
flag: true,
|
|
|
|
settings: ["foo1", "foo2", "foo3",],
|
|
|
|
perarch: {
|
|
|
|
arm: "32",
|
|
|
|
arm64: "64",
|
|
|
|
},
|
|
|
|
configvars: [
|
|
|
|
{ name: "var1", values: ["var1:1", "var1:2", ], },
|
|
|
|
{ name: "var2", values: ["var2:1", "var2:2", ], },
|
|
|
|
],
|
|
|
|
}
|
|
|
|
`
|
|
|
|
run(b, props, bp)
|
|
|
|
})
|
2016-06-01 00:53:32 +02:00
|
|
|
}
|
2023-10-30 22:48:37 +01:00
|
|
|
|
|
|
|
func TestRemoveUnnecessaryUnusedNames(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
input []string
|
|
|
|
output []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "no unused names",
|
|
|
|
input: []string{},
|
|
|
|
output: []string{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "only one unused name",
|
|
|
|
input: []string{"a.b.c"},
|
|
|
|
output: []string{"a.b.c"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unused names in a chain",
|
|
|
|
input: []string{"a", "a.b", "a.b.c"},
|
|
|
|
output: []string{"a.b.c"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unused names unrelated",
|
|
|
|
input: []string{"a.b.c", "s.t", "x.y"},
|
|
|
|
output: []string{"a.b.c", "s.t", "x.y"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unused names partially related one",
|
|
|
|
input: []string{"a.b", "a.b.c", "a.b.d"},
|
|
|
|
output: []string{"a.b.c", "a.b.d"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unused names partially related two",
|
|
|
|
input: []string{"a", "a.b.c", "a.c"},
|
|
|
|
output: []string{"a.b.c", "a.c"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unused names partially related three",
|
|
|
|
input: []string{"a.b.c", "b.c", "c"},
|
|
|
|
output: []string{"a.b.c", "b.c", "c"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
|
|
simplifiedNames := removeUnnecessaryUnusedNames(testCase.input)
|
|
|
|
if !reflect.DeepEqual(simplifiedNames, testCase.output) {
|
|
|
|
t.Errorf("test case: %s", testCase.name)
|
|
|
|
t.Errorf(" input: %s", testCase.input)
|
|
|
|
t.Errorf(" expect: %s", testCase.output)
|
|
|
|
t.Errorf(" got: %s", simplifiedNames)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|