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",
|
|
|
|
typ: parser.SelectTypeUnconfigured,
|
Add support for unset select branches
Currently, with the arch/os mutator, you can override a property
using the default value for just a few arch types, for example:
cc_defaults {
name: "my_defaults",
target: {
windows: {
enabled: true,
}
}
}
cc_binary {
name: "foo",
enabled: false,
defaults: ["my_defaults"],
}
You could make a select statment that acts like the above if it were
all in one module, but currently with select statements you can't make
a defaults module that can be generically applied to any other module
and have the same behavior as the above.
After this cl, the defaults module could look like:
cc_defaults {
name: "my_defaults",
enabled: select(variant("arch"), {
"windows": true,
_: unset,
}),
}
Which would have the same behavior. Unset may also be useful for
setting the property under some configurations, but wanting to leave
the implementation-specific default value in others.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: I3ea3277ea8b9a0ac5e613b4378945388b9df036a
2024-03-29 00:20:12 +01:00
|
|
|
cases: map[string]*string{
|
|
|
|
default_select_branch_name: 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
|
|
|
},
|
|
|
|
appendWrapper: &appendWrapper[string]{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Bool configurable property that isn't configured",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
foo: true,
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Foo Configurable[bool]
|
|
|
|
}{
|
|
|
|
Foo: Configurable[bool]{
|
|
|
|
propertyName: "foo",
|
|
|
|
typ: parser.SelectTypeUnconfigured,
|
Add support for unset select branches
Currently, with the arch/os mutator, you can override a property
using the default value for just a few arch types, for example:
cc_defaults {
name: "my_defaults",
target: {
windows: {
enabled: true,
}
}
}
cc_binary {
name: "foo",
enabled: false,
defaults: ["my_defaults"],
}
You could make a select statment that acts like the above if it were
all in one module, but currently with select statements you can't make
a defaults module that can be generically applied to any other module
and have the same behavior as the above.
After this cl, the defaults module could look like:
cc_defaults {
name: "my_defaults",
enabled: select(variant("arch"), {
"windows": true,
_: unset,
}),
}
Which would have the same behavior. Unset may also be useful for
setting the property under some configurations, but wanting to leave
the implementation-specific default value in others.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: I3ea3277ea8b9a0ac5e613b4378945388b9df036a
2024-03-29 00:20:12 +01:00
|
|
|
cases: map[string]*bool{
|
|
|
|
default_select_branch_name: 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
|
|
|
},
|
|
|
|
appendWrapper: &appendWrapper[bool]{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
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",
|
|
|
|
typ: parser.SelectTypeUnconfigured,
|
Add support for unset select branches
Currently, with the arch/os mutator, you can override a property
using the default value for just a few arch types, for example:
cc_defaults {
name: "my_defaults",
target: {
windows: {
enabled: true,
}
}
}
cc_binary {
name: "foo",
enabled: false,
defaults: ["my_defaults"],
}
You could make a select statment that acts like the above if it were
all in one module, but currently with select statements you can't make
a defaults module that can be generically applied to any other module
and have the same behavior as the above.
After this cl, the defaults module could look like:
cc_defaults {
name: "my_defaults",
enabled: select(variant("arch"), {
"windows": true,
_: unset,
}),
}
Which would have the same behavior. Unset may also be useful for
setting the property under some configurations, but wanting to leave
the implementation-specific default value in others.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: I3ea3277ea8b9a0ac5e613b4378945388b9df036a
2024-03-29 00:20:12 +01:00
|
|
|
cases: map[string]*[]string{
|
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
|
|
|
default_select_branch_name: {"a", "b"},
|
|
|
|
},
|
|
|
|
appendWrapper: &appendWrapper[[]string]{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Configurable property",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
foo: select(soong_config_variable("my_namespace", "my_variable"), {
|
|
|
|
"a": "a2",
|
|
|
|
"b": "b2",
|
|
|
|
_: "c2",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Foo Configurable[string]
|
|
|
|
}{
|
|
|
|
Foo: Configurable[string]{
|
|
|
|
propertyName: "foo",
|
|
|
|
typ: parser.SelectTypeSoongConfigVariable,
|
|
|
|
condition: "my_namespace:my_variable",
|
Add support for unset select branches
Currently, with the arch/os mutator, you can override a property
using the default value for just a few arch types, for example:
cc_defaults {
name: "my_defaults",
target: {
windows: {
enabled: true,
}
}
}
cc_binary {
name: "foo",
enabled: false,
defaults: ["my_defaults"],
}
You could make a select statment that acts like the above if it were
all in one module, but currently with select statements you can't make
a defaults module that can be generically applied to any other module
and have the same behavior as the above.
After this cl, the defaults module could look like:
cc_defaults {
name: "my_defaults",
enabled: select(variant("arch"), {
"windows": true,
_: unset,
}),
}
Which would have the same behavior. Unset may also be useful for
setting the property under some configurations, but wanting to leave
the implementation-specific default value in others.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: I3ea3277ea8b9a0ac5e613b4378945388b9df036a
2024-03-29 00:20:12 +01:00
|
|
|
cases: map[string]*string{
|
|
|
|
"a": StringPtr("a2"),
|
|
|
|
"b": StringPtr("b2"),
|
|
|
|
default_select_branch_name: StringPtr("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
|
|
|
},
|
|
|
|
appendWrapper: &appendWrapper[string]{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Configurable property appending",
|
|
|
|
input: `
|
|
|
|
m {
|
|
|
|
foo: select(soong_config_variable("my_namespace", "my_variable"), {
|
|
|
|
"a": "a2",
|
|
|
|
"b": "b2",
|
|
|
|
_: "c2",
|
|
|
|
}) + select(soong_config_variable("my_namespace", "my_2nd_variable"), {
|
|
|
|
"d": "d2",
|
|
|
|
"e": "e2",
|
|
|
|
_: "f2",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
output: []interface{}{
|
|
|
|
&struct {
|
|
|
|
Foo Configurable[string]
|
|
|
|
}{
|
|
|
|
Foo: Configurable[string]{
|
|
|
|
propertyName: "foo",
|
|
|
|
typ: parser.SelectTypeSoongConfigVariable,
|
|
|
|
condition: "my_namespace:my_variable",
|
Add support for unset select branches
Currently, with the arch/os mutator, you can override a property
using the default value for just a few arch types, for example:
cc_defaults {
name: "my_defaults",
target: {
windows: {
enabled: true,
}
}
}
cc_binary {
name: "foo",
enabled: false,
defaults: ["my_defaults"],
}
You could make a select statment that acts like the above if it were
all in one module, but currently with select statements you can't make
a defaults module that can be generically applied to any other module
and have the same behavior as the above.
After this cl, the defaults module could look like:
cc_defaults {
name: "my_defaults",
enabled: select(variant("arch"), {
"windows": true,
_: unset,
}),
}
Which would have the same behavior. Unset may also be useful for
setting the property under some configurations, but wanting to leave
the implementation-specific default value in others.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: I3ea3277ea8b9a0ac5e613b4378945388b9df036a
2024-03-29 00:20:12 +01:00
|
|
|
cases: map[string]*string{
|
|
|
|
"a": StringPtr("a2"),
|
|
|
|
"b": StringPtr("b2"),
|
|
|
|
default_select_branch_name: StringPtr("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
|
|
|
},
|
|
|
|
appendWrapper: &appendWrapper[string]{
|
|
|
|
append: Configurable[string]{
|
|
|
|
propertyName: "foo",
|
|
|
|
typ: parser.SelectTypeSoongConfigVariable,
|
|
|
|
condition: "my_namespace:my_2nd_variable",
|
Add support for unset select branches
Currently, with the arch/os mutator, you can override a property
using the default value for just a few arch types, for example:
cc_defaults {
name: "my_defaults",
target: {
windows: {
enabled: true,
}
}
}
cc_binary {
name: "foo",
enabled: false,
defaults: ["my_defaults"],
}
You could make a select statment that acts like the above if it were
all in one module, but currently with select statements you can't make
a defaults module that can be generically applied to any other module
and have the same behavior as the above.
After this cl, the defaults module could look like:
cc_defaults {
name: "my_defaults",
enabled: select(variant("arch"), {
"windows": true,
_: unset,
}),
}
Which would have the same behavior. Unset may also be useful for
setting the property under some configurations, but wanting to leave
the implementation-specific default value in others.
Bug: 323382414
Test: m nothing --no-skip-soong-tests
Change-Id: I3ea3277ea8b9a0ac5e613b4378945388b9df036a
2024-03-29 00:20:12 +01:00
|
|
|
cases: map[string]*string{
|
|
|
|
"d": StringPtr("d2"),
|
|
|
|
"e": StringPtr("e2"),
|
|
|
|
default_select_branch_name: StringPtr("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
|
|
|
},
|
|
|
|
appendWrapper: &appendWrapper[string]{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
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)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|