platform_build_blueprint/proptools/clone_test.go
Nan Zhang f586544ab7 Support parsing int64 in Blueprint file.
Support int64 number instead of int to be more fixed to bit size so
that the underlying arch won't affect overflow cases. Besides,
refection: func (v Value) Int() int64 always cast to int64 no matter the
input is int, int16, int32. Currently we always treat "-" as negative
sign to bind to next value, and "+" as plus operator to add operands
together.
So we allow:
a = 5 + -4 + 5 or a = -4 + 5
But we don't allow:
a = +5 + 4 + -4 since we don't treat "+" as a positive sign, otherwise,
a = 5 + +5 would exist which looks pretty weird. In the future, we may
want fully support number calculator logic eg, "+"/"-" can be
positive/negative sign or operator, and "(" and ")" will be considered
to group expressions with a higher precedence.

int & uint properties within struct keeps unchanged, which is only
allowed when tagged with 'blueprint:mutated'. We only allow *int64
property instead of int64 property within struct since it does't make
sense to do prepending or appending to int64.

Change-Id: I565e046dbd268af3538aee148cd7300037e56523
2017-11-02 22:10:47 -07:00

503 lines
9.2 KiB
Go

// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package proptools
import (
"fmt"
"reflect"
"testing"
)
var clonePropertiesTestCases = []struct {
in interface{}
out interface{}
err error
}{
// Valid inputs
{
// Clone bool
in: &struct{ B1, B2 bool }{
B1: true,
B2: false,
},
out: &struct{ B1, B2 bool }{
B1: true,
B2: false,
},
},
{
// Clone strings
in: &struct{ S string }{
S: "string1",
},
out: &struct{ S string }{
S: "string1",
},
},
{
// Clone slice
in: &struct{ S []string }{
S: []string{"string1"},
},
out: &struct{ S []string }{
S: []string{"string1"},
},
},
{
// Clone empty slice
in: &struct{ S []string }{
S: []string{},
},
out: &struct{ S []string }{
S: []string{},
},
},
{
// Clone nil slice
in: &struct{ S []string }{},
out: &struct{ S []string }{},
},
{
// Clone pointer to bool
in: &struct{ B1, B2 *bool }{
B1: BoolPtr(true),
B2: BoolPtr(false),
},
out: &struct{ B1, B2 *bool }{
B1: BoolPtr(true),
B2: BoolPtr(false),
},
},
{
// Clone pointer to string
in: &struct{ S *string }{
S: StringPtr("string1"),
},
out: &struct{ S *string }{
S: StringPtr("string1"),
},
},
{
// Clone pointer to int64
in: &struct{ S *int64 }{
S: Int64Ptr(5),
},
out: &struct{ S *int64 }{
S: Int64Ptr(5),
},
},
{
// Clone struct
in: &struct{ S struct{ S string } }{
S: struct{ S string }{
S: "string1",
},
},
out: &struct{ S struct{ S string } }{
S: struct{ S string }{
S: "string1",
},
},
},
{
// Clone struct pointer
in: &struct{ S *struct{ S string } }{
S: &struct{ S string }{
S: "string1",
},
},
out: &struct{ S *struct{ S string } }{
S: &struct{ S string }{
S: "string1",
},
},
},
{
// Clone interface
in: &struct{ S interface{} }{
S: &struct{ S string }{
S: "string1",
},
},
out: &struct{ S interface{} }{
S: &struct{ S string }{
S: "string1",
},
},
},
{
// Clone nested interface
in: &struct {
Nested struct{ S interface{} }
}{
Nested: struct{ S interface{} }{
S: &struct{ S string }{
S: "string1",
},
},
},
out: &struct {
Nested struct{ S interface{} }
}{
Nested: struct{ S interface{} }{
S: &struct{ S string }{
S: "string1",
},
},
},
}, {
// Empty struct
in: &struct{}{},
out: &struct{}{},
},
{
// Interface nil
in: &struct{ S interface{} }{
S: nil,
},
out: &struct{ S interface{} }{
S: nil,
},
},
{
// Interface pointer to nil
in: &struct{ S interface{} }{
S: (*struct{ S string })(nil),
},
out: &struct{ S interface{} }{
S: (*struct{ S string })(nil),
},
},
{
// Pointer nil
in: &struct{ S *struct{} }{
S: nil,
},
out: &struct{ S *struct{} }{
S: nil,
},
},
{
// Anonymous struct
in: &struct {
EmbeddedStruct
Nested struct{ EmbeddedStruct }
}{
EmbeddedStruct: EmbeddedStruct{
S: "string1",
I: Int64Ptr(55),
},
Nested: struct{ EmbeddedStruct }{
EmbeddedStruct: EmbeddedStruct{
S: "string2",
I: Int64Ptr(5),
},
},
},
out: &struct {
EmbeddedStruct
Nested struct{ EmbeddedStruct }
}{
EmbeddedStruct: EmbeddedStruct{
S: "string1",
I: Int64Ptr(55),
},
Nested: struct{ EmbeddedStruct }{
EmbeddedStruct: EmbeddedStruct{
S: "string2",
I: Int64Ptr(5),
},
},
},
},
{
// Anonymous interface
in: &struct {
EmbeddedInterface
Nested struct{ EmbeddedInterface }
}{
EmbeddedInterface: &struct{ S string }{
S: "string1",
},
Nested: struct{ EmbeddedInterface }{
EmbeddedInterface: &struct{ S string }{
S: "string2",
},
},
},
out: &struct {
EmbeddedInterface
Nested struct{ EmbeddedInterface }
}{
EmbeddedInterface: &struct{ S string }{
S: "string1",
},
Nested: struct{ EmbeddedInterface }{
EmbeddedInterface: &struct{ S string }{
S: "string2",
},
},
},
},
}
type EmbeddedStruct struct {
S string
I *int64
}
type EmbeddedInterface interface{}
func TestCloneProperties(t *testing.T) {
for _, testCase := range clonePropertiesTestCases {
testString := fmt.Sprintf("%s", testCase.in)
got := CloneProperties(reflect.ValueOf(testCase.in).Elem()).Interface()
if !reflect.DeepEqual(testCase.out, got) {
t.Errorf("test case %s", testString)
t.Errorf("incorrect output")
t.Errorf(" expected: %#v", testCase.out)
t.Errorf(" got: %#v", got)
}
}
}
var cloneEmptyPropertiesTestCases = []struct {
in interface{}
out interface{}
err error
}{
// Valid inputs
{
// Clone bool
in: &struct{ B1, B2 bool }{
B1: true,
B2: false,
},
out: &struct{ B1, B2 bool }{},
},
{
// Clone strings
in: &struct{ S string }{
S: "string1",
},
out: &struct{ S string }{},
},
{
// Clone slice
in: &struct{ S []string }{
S: []string{"string1"},
},
out: &struct{ S []string }{},
},
{
// Clone empty slice
in: &struct{ S []string }{
S: []string{},
},
out: &struct{ S []string }{},
},
{
// Clone nil slice
in: &struct{ S []string }{},
out: &struct{ S []string }{},
},
{
// Clone pointer to bool
in: &struct{ B1, B2 *bool }{
B1: BoolPtr(true),
B2: BoolPtr(false),
},
out: &struct{ B1, B2 *bool }{},
},
{
// Clone pointer to int64
in: &struct{ B1, B2 *int64 }{
B1: Int64Ptr(5),
B2: Int64Ptr(4),
},
out: &struct{ B1, B2 *int64 }{},
},
{
// Clone pointer to string
in: &struct{ S *string }{
S: StringPtr("string1"),
},
out: &struct{ S *string }{},
},
{
// Clone struct
in: &struct{ S struct{ S string } }{
S: struct{ S string }{
S: "string1",
},
},
out: &struct{ S struct{ S string } }{
S: struct{ S string }{},
},
},
{
// Clone struct pointer
in: &struct{ S *struct{ S string } }{
S: &struct{ S string }{
S: "string1",
},
},
out: &struct{ S *struct{ S string } }{
S: &struct{ S string }{},
},
},
{
// Clone interface
in: &struct{ S interface{} }{
S: &struct{ S string }{
S: "string1",
},
},
out: &struct{ S interface{} }{
S: &struct{ S string }{},
},
},
{
// Clone nested interface
in: &struct {
Nested struct{ S interface{} }
}{
Nested: struct{ S interface{} }{
S: &struct{ S string }{
S: "string1",
},
},
},
out: &struct {
Nested struct{ S interface{} }
}{
Nested: struct{ S interface{} }{
S: &struct{ S string }{},
},
},
},
{
// Empty struct
in: &struct{}{},
out: &struct{}{},
},
{
// Interface nil
in: &struct{ S interface{} }{
S: nil,
},
out: &struct{ S interface{} }{},
},
{
// Interface pointer to nil
in: &struct{ S interface{} }{
S: (*struct{ S string })(nil),
},
out: &struct{ S interface{} }{
S: (*struct{ S string })(nil),
},
},
{
// Pointer nil
in: &struct{ S *struct{} }{
S: nil,
},
out: &struct{ S *struct{} }{},
},
{
// Anonymous struct
in: &struct {
EmbeddedStruct
Nested struct{ EmbeddedStruct }
}{
EmbeddedStruct: EmbeddedStruct{
S: "string1",
},
Nested: struct{ EmbeddedStruct }{
EmbeddedStruct: EmbeddedStruct{
S: "string2",
},
},
},
out: &struct {
EmbeddedStruct
Nested struct{ EmbeddedStruct }
}{
EmbeddedStruct: EmbeddedStruct{},
Nested: struct{ EmbeddedStruct }{
EmbeddedStruct: EmbeddedStruct{},
},
},
},
{
// Anonymous interface
in: &struct {
EmbeddedInterface
Nested struct{ EmbeddedInterface }
}{
EmbeddedInterface: &struct{ S string }{
S: "string1",
},
Nested: struct{ EmbeddedInterface }{
EmbeddedInterface: &struct{ S string }{
S: "string2",
},
},
},
out: &struct {
EmbeddedInterface
Nested struct{ EmbeddedInterface }
}{
EmbeddedInterface: &struct{ S string }{},
Nested: struct{ EmbeddedInterface }{
EmbeddedInterface: &struct{ S string }{},
},
},
},
}
func TestCloneEmptyProperties(t *testing.T) {
for _, testCase := range cloneEmptyPropertiesTestCases {
testString := fmt.Sprintf("%#v", testCase.in)
got := CloneEmptyProperties(reflect.ValueOf(testCase.in).Elem()).Interface()
if !reflect.DeepEqual(testCase.out, got) {
t.Errorf("test case %s", testString)
t.Errorf("incorrect output")
t.Errorf(" expected: %#v", testCase.out)
t.Errorf(" got: %#v", got)
}
}
}
func TestZeroProperties(t *testing.T) {
for _, testCase := range cloneEmptyPropertiesTestCases {
testString := fmt.Sprintf("%#v", testCase.in)
got := CloneProperties(reflect.ValueOf(testCase.in).Elem()).Interface()
ZeroProperties(reflect.ValueOf(got).Elem())
if !reflect.DeepEqual(testCase.out, got) {
t.Errorf("test case %s", testString)
t.Errorf("incorrect output")
t.Errorf(" expected: %#v", testCase.out)
t.Errorf(" got: %#v", got)
}
}
}