Merge remote-tracking branch 'aosp/upstream' into master am: 86286b9ac9 am: 2ad0aebc37

Change-Id: If811a4aff87b0be85e0519925bfb7938024c22c0
This commit is contained in:
Automerger Merge Worker 2020-01-06 23:03:12 +00:00
commit e356e519fd
10 changed files with 300 additions and 126 deletions

View file

@ -19,7 +19,6 @@ bootstrap_go_package {
"package_ctx.go",
"scope.go",
"singleton_ctx.go",
"unpack.go",
],
testSrcs: [
"context_test.go",
@ -28,7 +27,6 @@ bootstrap_go_package {
"ninja_strings_test.go",
"ninja_writer_test.go",
"splice_modules_test.go",
"unpack_test.go",
"visit_test.go",
],
}
@ -76,6 +74,9 @@ bootstrap_go_package {
bootstrap_go_package {
name: "blueprint-proptools",
pkgPath: "github.com/google/blueprint/proptools",
deps: [
"blueprint-parser",
],
srcs: [
"proptools/clone.go",
"proptools/escape.go",
@ -84,6 +85,7 @@ bootstrap_go_package {
"proptools/proptools.go",
"proptools/tag.go",
"proptools/typeequal.go",
"proptools/unpack.go",
],
testSrcs: [
"proptools/clone_test.go",
@ -92,6 +94,7 @@ bootstrap_go_package {
"proptools/filter_test.go",
"proptools/tag_test.go",
"proptools/typeequal_test.go",
"proptools/unpack_test.go",
],
}

View file

@ -6,7 +6,6 @@ import (
"reflect"
"sort"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@ -146,7 +145,7 @@ func assembleModuleTypeInfo(r *Reader, name string, factory reflect.Value,
return nil, fmt.Errorf("nesting point %q not found", nestedName)
}
key, value, err := blueprint.HasFilter(nestPoint.Tag)
key, value, err := proptools.HasFilter(nestPoint.Tag)
if err != nil {
return nil, err
}

View file

@ -140,7 +140,7 @@ func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...stri
ctx.RegisterSingletonType("glob", globSingletonFactory(ctx))
deps, errs := ctx.ParseFileList(filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), filesToParse)
deps, errs := ctx.ParseFileList(filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), filesToParse, config)
if len(errs) > 0 {
fatalErrors(errs)
}

View file

@ -631,17 +631,19 @@ type fileParseContext struct {
// which the future output will depend is returned. This list will include both
// Blueprints file paths as well as directory paths for cases where wildcard
// subdirs are found.
func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string, errs []error) {
func (c *Context) ParseBlueprintsFiles(rootFile string,
config interface{}) (deps []string, errs []error) {
baseDir := filepath.Dir(rootFile)
pathsToParse, err := c.ListModulePaths(baseDir)
if err != nil {
return nil, []error{err}
}
return c.ParseFileList(baseDir, pathsToParse)
return c.ParseFileList(baseDir, pathsToParse, config)
}
func (c *Context) ParseFileList(rootDir string, filePaths []string) (deps []string,
errs []error) {
func (c *Context) ParseFileList(rootDir string, filePaths []string,
config interface{}) (deps []string, errs []error) {
if len(filePaths) < 1 {
return nil, []error{fmt.Errorf("no paths provided to parse")}
@ -649,7 +651,12 @@ func (c *Context) ParseFileList(rootDir string, filePaths []string) (deps []stri
c.dependenciesReady = false
moduleCh := make(chan *moduleInfo)
type newModuleInfo struct {
*moduleInfo
added chan<- struct{}
}
moduleCh := make(chan newModuleInfo)
errsCh := make(chan []error)
doneCh := make(chan struct{})
var numErrs uint32
@ -661,24 +668,47 @@ func (c *Context) ParseFileList(rootDir string, filePaths []string) (deps []stri
return
}
addedCh := make(chan struct{})
var scopedModuleFactories map[string]ModuleFactory
var addModule func(module *moduleInfo) []error
addModule = func(module *moduleInfo) (errs []error) {
moduleCh <- newModuleInfo{module, addedCh}
<-addedCh
var newModules []*moduleInfo
newModules, errs = runAndRemoveLoadHooks(c, config, module, &scopedModuleFactories)
if len(errs) > 0 {
return errs
}
for _, n := range newModules {
errs = addModule(n)
if len(errs) > 0 {
return errs
}
}
return nil
}
for _, def := range file.Defs {
var module *moduleInfo
var errs []error
switch def := def.(type) {
case *parser.Module:
module, errs = c.processModuleDef(def, file.Name)
module, errs := c.processModuleDef(def, file.Name, scopedModuleFactories)
if len(errs) == 0 && module != nil {
errs = addModule(module)
}
if len(errs) > 0 {
atomic.AddUint32(&numErrs, uint32(len(errs)))
errsCh <- errs
}
case *parser.Assignment:
// Already handled via Scope object
default:
panic("unknown definition type")
}
if len(errs) > 0 {
atomic.AddUint32(&numErrs, uint32(len(errs)))
errsCh <- errs
} else if module != nil {
moduleCh <- module
}
}
}
@ -698,7 +728,10 @@ loop:
case newErrs := <-errsCh:
errs = append(errs, newErrs...)
case module := <-moduleCh:
newErrs := c.addModule(module)
newErrs := c.addModule(module.moduleInfo)
if module.added != nil {
module.added <- struct{}{}
}
if len(newErrs) > 0 {
errs = append(errs, newErrs...)
}
@ -1307,9 +1340,12 @@ func (c *Context) newModule(factory ModuleFactory) *moduleInfo {
}
func (c *Context) processModuleDef(moduleDef *parser.Module,
relBlueprintsFile string) (*moduleInfo, []error) {
relBlueprintsFile string, scopedModuleFactories map[string]ModuleFactory) (*moduleInfo, []error) {
factory, ok := c.moduleFactories[moduleDef.Type]
if !ok && scopedModuleFactories != nil {
factory, ok = scopedModuleFactories[moduleDef.Type]
}
if !ok {
if c.ignoreUnknownModuleTypes {
return nil, nil
@ -1328,8 +1364,17 @@ func (c *Context) processModuleDef(moduleDef *parser.Module,
module.relBlueprintsFile = relBlueprintsFile
propertyMap, errs := unpackProperties(moduleDef.Properties, module.properties...)
propertyMap, errs := proptools.UnpackProperties(moduleDef.Properties, module.properties...)
if len(errs) > 0 {
for i, err := range errs {
if unpackErr, ok := err.(*proptools.UnpackError); ok {
err = &BlueprintError{
Err: unpackErr.Err,
Pos: unpackErr.Pos,
}
errs[i] = err
}
}
return nil, errs
}

View file

@ -168,7 +168,7 @@ func TestWalkDeps(t *testing.T) {
ctx.RegisterModuleType("foo_module", newFooModule)
ctx.RegisterModuleType("bar_module", newBarModule)
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
if len(errs) > 0 {
t.Errorf("unexpected parse errors:")
for _, err := range errs {
@ -260,7 +260,7 @@ func TestWalkDepsDuplicates(t *testing.T) {
ctx.RegisterModuleType("foo_module", newFooModule)
ctx.RegisterModuleType("bar_module", newBarModule)
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
if len(errs) > 0 {
t.Errorf("unexpected parse errors:")
for _, err := range errs {
@ -316,7 +316,7 @@ func TestCreateModule(t *testing.T) {
ctx.RegisterModuleType("foo_module", newFooModule)
ctx.RegisterModuleType("bar_module", newBarModule)
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
if len(errs) > 0 {
t.Errorf("unexpected parse errors:")
for _, err := range errs {
@ -499,7 +499,7 @@ func TestParseFailsForModuleWithoutName(t *testing.T) {
ctx.RegisterModuleType("foo_module", newFooModule)
ctx.RegisterModuleType("bar_module", newBarModule)
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
expectedErrs := []error{
errors.New(`Blueprints:6:4: property 'name' is missing from a module`),

View file

@ -17,6 +17,7 @@ package blueprint
import (
"fmt"
"path/filepath"
"sync"
"text/scanner"
"github.com/google/blueprint/pathtools"
@ -120,7 +121,7 @@ type DynamicDependerModule interface {
DynamicDependencies(DynamicDependerModuleContext) []string
}
type BaseModuleContext interface {
type EarlyModuleContext interface {
// Module returns the current module as a Module. It should rarely be necessary, as the module already has a
// reference to itself.
Module() Module
@ -179,6 +180,13 @@ type BaseModuleContext interface {
// default SimpleNameInterface if Context.SetNameInterface was not called.
Namespace() Namespace
// ModuleFactories returns a map of all of the global ModuleFactories by name.
ModuleFactories() map[string]ModuleFactory
}
type BaseModuleContext interface {
EarlyModuleContext
// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
// none exists. It panics if the dependency does not have the specified tag.
GetDirectDepWithTag(name string, tag DependencyTag) Module
@ -597,6 +605,14 @@ func (m *baseModuleContext) AddNinjaFileDeps(deps ...string) {
m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
}
func (m *baseModuleContext) ModuleFactories() map[string]ModuleFactory {
ret := make(map[string]ModuleFactory)
for k, v := range m.context.moduleFactories {
ret[k] = v
}
return ret
}
func (m *moduleContext) ModuleSubDir() string {
return m.module.variantName
}
@ -995,3 +1011,107 @@ type SimpleName struct {
func (s *SimpleName) Name() string {
return s.Properties.Name
}
// Load Hooks
type LoadHookContext interface {
EarlyModuleContext
// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
// the specified property structs to it as if the properties were set in a blueprint file.
CreateModule(ModuleFactory, ...interface{}) Module
// RegisterScopedModuleType creates a new module type that is scoped to the current Blueprints
// file.
RegisterScopedModuleType(name string, factory ModuleFactory)
}
func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
module := l.context.newModule(factory)
module.relBlueprintsFile = l.module.relBlueprintsFile
module.pos = l.module.pos
module.propertyPos = l.module.propertyPos
module.createdBy = l.module
for _, p := range props {
err := proptools.AppendMatchingProperties(module.properties, p, nil)
if err != nil {
panic(err)
}
}
l.newModules = append(l.newModules, module)
return module.logicModule
}
func (l *loadHookContext) RegisterScopedModuleType(name string, factory ModuleFactory) {
if _, exists := l.context.moduleFactories[name]; exists {
panic(fmt.Errorf("A global module type named %q already exists", name))
}
if _, exists := (*l.scopedModuleFactories)[name]; exists {
panic(fmt.Errorf("A module type named %q already exists in this scope", name))
}
if *l.scopedModuleFactories == nil {
(*l.scopedModuleFactories) = make(map[string]ModuleFactory)
}
(*l.scopedModuleFactories)[name] = factory
}
type loadHookContext struct {
baseModuleContext
newModules []*moduleInfo
scopedModuleFactories *map[string]ModuleFactory
}
type LoadHook func(ctx LoadHookContext)
// Load hooks need to be added by module factories, which don't have any parameter to get to the
// Context, and only produce a Module interface with no base implementation, so the load hooks
// must be stored in a global map. The key is a pointer allocated by the module factory, so there
// is no chance of collisions even if tests are running in parallel with multiple contexts. The
// contents should be short-lived, they are added during a module factory and removed immediately
// after the module factory returns.
var pendingHooks sync.Map
func AddLoadHook(module Module, hook LoadHook) {
// Only one goroutine can be processing a given module, so no additional locking is required
// for the slice stored in the sync.Map.
v, exists := pendingHooks.Load(module)
if !exists {
v, _ = pendingHooks.LoadOrStore(module, new([]LoadHook))
}
hooks := v.(*[]LoadHook)
*hooks = append(*hooks, hook)
}
func runAndRemoveLoadHooks(ctx *Context, config interface{}, module *moduleInfo,
scopedModuleFactories *map[string]ModuleFactory) (newModules []*moduleInfo, errs []error) {
if v, exists := pendingHooks.Load(module.logicModule); exists {
hooks := v.(*[]LoadHook)
mctx := &loadHookContext{
baseModuleContext: baseModuleContext{
context: ctx,
config: config,
module: module,
},
scopedModuleFactories: scopedModuleFactories,
}
for _, hook := range *hooks {
hook(mctx)
newModules = append(newModules, mctx.newModules...)
errs = append(errs, mctx.errs...)
}
pendingHooks.Delete(module.logicModule)
return newModules, errs
}
return nil, nil
}

View file

@ -76,7 +76,7 @@ func TestAliases(t *testing.T) {
ctx.MockFileSystem(mockFS)
_, errs := ctx.ParseFileList(".", []string{"Blueprints"})
_, errs := ctx.ParseFileList(".", []string{"Blueprints"}, nil)
if len(errs) > 0 {
t.Errorf("unexpected parse errors:")
for _, err := range errs {

View file

@ -12,24 +12,35 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package blueprint
package proptools
import (
"fmt"
"reflect"
"strconv"
"strings"
"text/scanner"
"github.com/google/blueprint/parser"
"github.com/google/blueprint/proptools"
)
const maxUnpackErrors = 10
type UnpackError struct {
Err error
Pos scanner.Position
}
func (e *UnpackError) Error() string {
return fmt.Sprintf("%s: %s", e.Pos, e.Err)
}
type packedProperty struct {
property *parser.Property
unpacked bool
}
func unpackProperties(propertyDefs []*parser.Property,
func UnpackProperties(propertyDefs []*parser.Property,
propertiesStructs ...interface{}) (map[string]*parser.Property, []error) {
propertyMap := make(map[string]*packedProperty)
@ -52,7 +63,7 @@ func unpackProperties(propertyDefs []*parser.Property,
newErrs := unpackStructValue("", propertiesValue, propertyMap, "", "")
errs = append(errs, newErrs...)
if len(errs) >= maxErrors {
if len(errs) >= maxUnpackErrors {
return nil, errs
}
}
@ -63,7 +74,7 @@ func unpackProperties(propertyDefs []*parser.Property,
for name, packedProperty := range propertyMap {
result[name] = packedProperty.property
if !packedProperty.unpacked {
err := &BlueprintError{
err := &UnpackError{
Err: fmt.Errorf("unrecognized property %q", name),
Pos: packedProperty.property.ColonPos,
}
@ -88,15 +99,15 @@ func buildPropertyMap(namePrefix string, propertyDefs []*parser.Property,
// We've already added this property.
continue
}
errs = append(errs, &BlueprintError{
errs = append(errs, &UnpackError{
Err: fmt.Errorf("property %q already defined", name),
Pos: propertyDef.ColonPos,
})
errs = append(errs, &BlueprintError{
errs = append(errs, &UnpackError{
Err: fmt.Errorf("<-- previous definition here"),
Pos: first.property.ColonPos,
})
if len(errs) >= maxErrors {
if len(errs) >= maxUnpackErrors {
return errs
}
continue
@ -142,7 +153,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
continue
}
propertyName := namePrefix + proptools.PropertyNameForField(field.Name)
propertyName := namePrefix + PropertyNameForField(field.Name)
if !fieldValue.CanSet() {
panic(fmt.Errorf("field %s is not settable", propertyName))
@ -163,7 +174,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
case reflect.Slice:
elemType := field.Type.Elem()
if elemType.Kind() != reflect.String {
if !proptools.HasTag(field, "blueprint", "mutated") {
if !HasTag(field, "blueprint", "mutated") {
panic(fmt.Errorf("field %s is a non-string slice", propertyName))
}
}
@ -195,7 +206,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
}
case reflect.Int, reflect.Uint:
if !proptools.HasTag(field, "blueprint", "mutated") {
if !HasTag(field, "blueprint", "mutated") {
panic(fmt.Errorf(`int field %s must be tagged blueprint:"mutated"`, propertyName))
}
@ -216,25 +227,25 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
packedProperty.unpacked = true
if proptools.HasTag(field, "blueprint", "mutated") {
if HasTag(field, "blueprint", "mutated") {
errs = append(errs,
&BlueprintError{
&UnpackError{
Err: fmt.Errorf("mutated field %s cannot be set in a Blueprint file", propertyName),
Pos: packedProperty.property.ColonPos,
})
if len(errs) >= maxErrors {
if len(errs) >= maxUnpackErrors {
return errs
}
continue
}
if filterKey != "" && !proptools.HasTag(field, filterKey, filterValue) {
if filterKey != "" && !HasTag(field, filterKey, filterValue) {
errs = append(errs,
&BlueprintError{
&UnpackError{
Err: fmt.Errorf("filtered field %s cannot be set in a Blueprint file", propertyName),
Pos: packedProperty.property.ColonPos,
})
if len(errs) >= maxErrors {
if len(errs) >= maxUnpackErrors {
return errs
}
continue
@ -246,14 +257,14 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
localFilterKey, localFilterValue := filterKey, filterValue
if k, v, err := HasFilter(field.Tag); err != nil {
errs = append(errs, err)
if len(errs) >= maxErrors {
if len(errs) >= maxUnpackErrors {
return errs
}
} else if k != "" {
if filterKey != "" {
errs = append(errs, fmt.Errorf("nested filter tag not supported on field %q",
field.Name))
if len(errs) >= maxErrors {
if len(errs) >= maxUnpackErrors {
return errs
}
} else {
@ -264,7 +275,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
packedProperty.property, propertyMap, localFilterKey, localFilterValue)
errs = append(errs, newErrs...)
if len(errs) >= maxErrors {
if len(errs) >= maxUnpackErrors {
return errs
}
@ -276,12 +287,12 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
propertyValue, err := propertyToValue(fieldValue.Type(), packedProperty.property)
if err != nil {
errs = append(errs, err)
if len(errs) >= maxErrors {
if len(errs) >= maxUnpackErrors {
return errs
}
}
proptools.ExtendBasicType(fieldValue, propertyValue, proptools.Append)
ExtendBasicType(fieldValue, propertyValue, Append)
}
return errs

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package blueprint
package proptools
import (
"bytes"
@ -22,7 +22,6 @@ import (
"text/scanner"
"github.com/google/blueprint/parser"
"github.com/google/blueprint/proptools"
)
var validUnpackTestCases = []struct {
@ -34,18 +33,18 @@ var validUnpackTestCases = []struct {
{
input: `
m {
name: "abc",
s: "abc",
blank: "",
}
`,
output: []interface{}{
struct {
Name *string
S *string
Blank *string
Unset *string
}{
Name: proptools.StringPtr("abc"),
Blank: proptools.StringPtr(""),
S: StringPtr("abc"),
Blank: StringPtr(""),
Unset: nil,
},
},
@ -54,14 +53,14 @@ var validUnpackTestCases = []struct {
{
input: `
m {
name: "abc",
s: "abc",
}
`,
output: []interface{}{
struct {
Name string
S string
}{
Name: "abc",
S: "abc",
},
},
},
@ -94,8 +93,8 @@ var validUnpackTestCases = []struct {
IsBad *bool
IsUgly *bool
}{
IsGood: proptools.BoolPtr(true),
IsBad: proptools.BoolPtr(false),
IsGood: BoolPtr(true),
IsBad: BoolPtr(false),
IsUgly: nil,
},
},
@ -128,18 +127,18 @@ var validUnpackTestCases = []struct {
input: `
m {
nested: {
name: "abc",
s: "abc",
}
}
`,
output: []interface{}{
struct {
Nested struct {
Name string
S string
}
}{
Nested: struct{ Name string }{
Name: "abc",
Nested: struct{ S string }{
S: "abc",
},
},
},
@ -149,7 +148,7 @@ var validUnpackTestCases = []struct {
input: `
m {
nested: {
name: "def",
s: "def",
}
}
`,
@ -157,8 +156,8 @@ var validUnpackTestCases = []struct {
struct {
Nested interface{}
}{
Nested: &struct{ Name string }{
Name: "def",
Nested: &struct{ S string }{
S: "def",
},
},
},
@ -246,7 +245,7 @@ var validUnpackTestCases = []struct {
},
},
errs: []error{
&BlueprintError{
&UnpackError{
Err: fmt.Errorf("filtered field nested.foo cannot be set in a Blueprint file"),
Pos: mkpos(30, 4, 9),
},
@ -257,9 +256,9 @@ var validUnpackTestCases = []struct {
{
input: `
m {
name: "abc",
s: "abc",
nested: {
name: "def",
s: "def",
},
}
`,
@ -271,13 +270,13 @@ var validUnpackTestCases = []struct {
}
}{
EmbeddedStruct: EmbeddedStruct{
Name: "abc",
S: "abc",
},
Nested: struct {
EmbeddedStruct
}{
EmbeddedStruct: EmbeddedStruct{
Name: "def",
S: "def",
},
},
},
@ -288,9 +287,9 @@ var validUnpackTestCases = []struct {
{
input: `
m {
name: "abc",
s: "abc",
nested: {
name: "def",
s: "def",
},
}
`,
@ -301,14 +300,14 @@ var validUnpackTestCases = []struct {
EmbeddedInterface
}
}{
EmbeddedInterface: &struct{ Name string }{
Name: "abc",
EmbeddedInterface: &struct{ S string }{
S: "abc",
},
Nested: struct {
EmbeddedInterface
}{
EmbeddedInterface: &struct{ Name string }{
Name: "def",
EmbeddedInterface: &struct{ S string }{
S: "def",
},
},
},
@ -319,32 +318,32 @@ var validUnpackTestCases = []struct {
{
input: `
m {
name: "abc",
s: "abc",
nested: {
name: "def",
s: "def",
},
}
`,
output: []interface{}{
struct {
Name string
S string
EmbeddedStruct
Nested struct {
Name string
S string
EmbeddedStruct
}
}{
Name: "abc",
S: "abc",
EmbeddedStruct: EmbeddedStruct{
Name: "abc",
S: "abc",
},
Nested: struct {
Name string
S string
EmbeddedStruct
}{
Name: "def",
S: "def",
EmbeddedStruct: EmbeddedStruct{
Name: "def",
S: "def",
},
},
},
@ -355,32 +354,32 @@ var validUnpackTestCases = []struct {
{
input: `
m {
name: "abc",
s: "abc",
nested: {
name: "def",
s: "def",
},
}
`,
output: []interface{}{
struct {
Name string
S string
EmbeddedInterface
Nested struct {
Name string
S string
EmbeddedInterface
}
}{
Name: "abc",
EmbeddedInterface: &struct{ Name string }{
Name: "abc",
S: "abc",
EmbeddedInterface: &struct{ S string }{
S: "abc",
},
Nested: struct {
Name string
S string
EmbeddedInterface
}{
Name: "def",
EmbeddedInterface: &struct{ Name string }{
Name: "def",
S: "def",
EmbeddedInterface: &struct{ S string }{
S: "def",
},
},
},
@ -394,18 +393,18 @@ var validUnpackTestCases = []struct {
string = "def"
list_with_variable = [string]
m {
name: string,
s: string,
list: list,
list2: list_with_variable,
}
`,
output: []interface{}{
struct {
Name string
S string
List []string
List2 []string
}{
Name: "def",
S: "def",
List: []string{"abc"},
List2: []string{"def"},
},
@ -417,27 +416,27 @@ var validUnpackTestCases = []struct {
input: `
m {
nested: {
name: "abc",
s: "abc",
}
}
`,
output: []interface{}{
struct {
Nested struct {
Name string
S string
}
}{
Nested: struct{ Name string }{
Name: "abc",
Nested: struct{ S string }{
S: "abc",
},
},
struct {
Nested struct {
Name string
S string
}
}{
Nested: struct{ Name string }{
Name: "abc",
Nested: struct{ S string }{
S: "abc",
},
},
struct {
@ -450,25 +449,25 @@ var validUnpackTestCases = []struct {
input: `
m {
nested: {
name: "abc",
s: "abc",
}
}
`,
output: []interface{}{
struct {
Nested *struct {
Name string
S string
}
}{
Nested: &struct{ Name string }{
Name: "abc",
Nested: &struct{ S string }{
S: "abc",
},
},
},
empty: []interface{}{
&struct {
Nested *struct {
Name string
S string
}
}{},
},
@ -479,7 +478,7 @@ var validUnpackTestCases = []struct {
input: `
m {
nested: {
name: "abc",
s: "abc",
}
}
`,
@ -488,7 +487,7 @@ var validUnpackTestCases = []struct {
Nested interface{}
}{
Nested: &EmbeddedStruct{
Name: "abc",
S: "abc",
},
},
},
@ -521,9 +520,9 @@ var validUnpackTestCases = []struct {
List []string
}{
String: "012abc",
String_ptr: proptools.StringPtr("abc"),
String_ptr: StringPtr("abc"),
Bool: true,
Bool_ptr: proptools.BoolPtr(false),
Bool_ptr: BoolPtr(false),
List: []string{"0", "1", "2", "a", "b", "c"},
},
},
@ -536,18 +535,15 @@ var validUnpackTestCases = []struct {
List []string
}{
String: "012",
String_ptr: proptools.StringPtr("012"),
String_ptr: StringPtr("012"),
Bool: true,
Bool_ptr: proptools.BoolPtr(true),
Bool_ptr: BoolPtr(true),
List: []string{"0", "1", "2"},
},
},
},
}
type EmbeddedStruct struct{ Name string }
type EmbeddedInterface interface{}
func TestUnpackProperties(t *testing.T) {
for _, testCase := range validUnpackTestCases {
r := bytes.NewBufferString(testCase.input)
@ -572,10 +568,10 @@ func TestUnpackProperties(t *testing.T) {
output = testCase.empty
} else {
for _, p := range testCase.output {
output = append(output, proptools.CloneEmptyProperties(reflect.ValueOf(p)).Interface())
output = append(output, CloneEmptyProperties(reflect.ValueOf(p)).Interface())
}
}
_, errs = unpackProperties(module.Properties, output...)
_, errs = UnpackProperties(module.Properties, output...)
if len(errs) != 0 && len(testCase.errs) == 0 {
t.Errorf("test case: %s", testCase.input)
t.Errorf("unexpected unpack errors:")

View file

@ -125,7 +125,7 @@ func setupVisitTest(t *testing.T) *Context {
`),
})
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
if len(errs) > 0 {
t.Errorf("unexpected parse errors:")
for _, err := range errs {