Skip to content

Commit

Permalink
Merge branch 'protobuf-fakeroot' into proto-sort-by-type
Browse files Browse the repository at this point in the history
  • Loading branch information
robshakir committed Feb 12, 2018
2 parents 8f71ffc + d34da29 commit 2ef38fa
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 7 deletions.
17 changes: 17 additions & 0 deletions ygot/schema_tests/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2018 Google Inc.
//
// 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 schematest is used for testing with the default OpenConfig generated
// structs.
package schematest
110 changes: 110 additions & 0 deletions ygot/schema_tests/schema_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright 2018 Google Inc.
//
// 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 schematest is used for testing with the default OpenConfig generated
// structs.
package schematest

import (
"fmt"
"testing"

"github.com/kylelemons/godebug/pretty"
"github.com/openconfig/ygot/exampleoc"
"github.com/openconfig/ygot/ygot"
)

func TestBuildEmptyEthernet(t *testing.T) {
got := &exampleoc.Interface_Ethernet{}
ygot.BuildEmptyTree(got)

wantEmpty := &exampleoc.Interface_Ethernet{
SwitchedVlan: &exampleoc.Interface_Ethernet_SwitchedVlan{},
Counters: &exampleoc.Interface_Ethernet_Counters{},
}

if diff := pretty.Compare(got, wantEmpty); diff != "" {
fmt.Printf("did not get expected output after BuildEmptyTree, diff(-got,+want):\n%s", diff)
}

got.AutoNegotiate = ygot.Bool(true)
ygot.PruneEmptyBranches(got)

wantPruned := &exampleoc.Interface_Ethernet{
AutoNegotiate: ygot.Bool(true),
}

if diff := pretty.Compare(got, wantPruned); diff != "" {
fmt.Printf("did not get expected output after PruneEmptyBranches, diff(-got,+want):\n%s", diff)
}
}

func TestBuildEmptyDevice(t *testing.T) {
got := &exampleoc.Device{}
ygot.BuildEmptyTree(got)

ni, err := got.NewNetworkInstance("DEFAULT")
if err != nil {
t.Fatalf("got unexpected error: %v", err)
}
ygot.BuildEmptyTree(ni)

p, err := ni.NewProtocol(exampleoc.OpenconfigPolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "15169")
if err != nil {
t.Fatalf("got unexpected error: %v", err)
}

ygot.BuildEmptyTree(p)

n, err := p.Bgp.NewNeighbor("192.0.2.1")
if err != nil {
t.Fatalf("got unexpected error: %v", err)
}
n.PeerAs = ygot.Uint32(42)
n.SendCommunity = exampleoc.OpenconfigBgp_CommunityType_STANDARD

p.Bgp.Global.As = ygot.Uint32(42)

ygot.PruneEmptyBranches(got)

want := &exampleoc.Device{
NetworkInstance: map[string]*exampleoc.NetworkInstance{
"DEFAULT": {
Name: ygot.String("DEFAULT"),
Protocol: map[exampleoc.NetworkInstance_Protocol_Key]*exampleoc.NetworkInstance_Protocol{
{exampleoc.OpenconfigPolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "15169"}: {
Identifier: exampleoc.OpenconfigPolicyTypes_INSTALL_PROTOCOL_TYPE_BGP,
Name: ygot.String("15169"),
Bgp: &exampleoc.NetworkInstance_Protocol_Bgp{
Global: &exampleoc.NetworkInstance_Protocol_Bgp_Global{
As: ygot.Uint32(42),
},
Neighbor: map[string]*exampleoc.NetworkInstance_Protocol_Bgp_Neighbor{
"192.0.2.1": {
NeighborAddress: ygot.String("192.0.2.1"),
PeerAs: ygot.Uint32(42),
SendCommunity: exampleoc.OpenconfigBgp_CommunityType_STANDARD,
},
},
},
},
},
},
},
}

if diff := pretty.Compare(got, want); diff != "" {
t.Errorf("did not get expected device struct, diff(-got,+want):\n%s", diff)
}
}
64 changes: 61 additions & 3 deletions ygot/struct_validation_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,14 @@ func PruneEmptyBranches(s GoStruct) {
// supplied reflect.Type, reflect.Value which must represent a GoStruct. An empty
// tree is defined to be a struct that is equal to its zero value. Only struct
// pointer fields are examined, since these are subtrees within the generated GoStruct
// types.
func pruneBranchesInternal(t reflect.Type, v reflect.Value) {
// types. It returns a bool which indicates whether all fields of the struct were
// removed.
func pruneBranchesInternal(t reflect.Type, v reflect.Value) bool {
// Track whether all fields of the GoStruct are nil, such that it can
// be returned to the caller. This allows parents that have all empty
// children to be removed. This is required because BuildEmptyTree will
// propagate to all branches.
allChildrenPruned := true
for i := 0; i < v.NumField(); i++ {
fVal := v.Field(i)
fType := t.Field(i)
Expand All @@ -196,10 +202,62 @@ func pruneBranchesInternal(t reflect.Type, v reflect.Value) {
// If this wasn't an empty struct then we need to recurse to remove
// any nil children of this struct.
sv := fVal.Elem()
pruneBranchesInternal(sv.Type(), sv)
childPruned := pruneBranchesInternal(sv.Type(), sv)
if childPruned {
// If all fields of the downstream branches are nil, then
// also prune this field.
fVal.Set(reflect.Zero(fType.Type))
} else {
allChildrenPruned = false
}
}
continue
}

// If the struct field wasn't a struct pointer, then we need to check whether it
// is the nil value of its type.
switch {
case util.IsTypeSlice(fType.Type):
if (fVal.Len() != 0) && allChildrenPruned {
allChildrenPruned = false
}
case util.IsTypeMap(fType.Type):
if fVal.Len() != 0 && allChildrenPruned {
allChildrenPruned = false
}

// Recurse into maps where the children may have already been initialised.
for _, k := range fVal.MapKeys() {
mi := fVal.MapIndex(k)
if !util.IsValueStructPtr(mi) {
continue
}
sv := mi.Elem()
// We can discard the pruneBranchesInternal return value, since we
// know that this map field has len > 0, and therefore cannot be
// pruned.
_ = pruneBranchesInternal(sv.Type(), sv)
}
default:
// Handle the case of a non-map/slice/struct pointer field.
v := fVal
t := fType.Type
if fType.Type.Kind() == reflect.Ptr {
if !v.IsNil() {
allChildrenPruned = false
continue
}
// Dereference the pointer to allow a zero check.
v = v.Elem()
t = t.Elem()
}
if v.IsValid() && !reflect.DeepEqual(reflect.Zero(t).Interface(), v.Interface()) {
allChildrenPruned = false
}
}

}
return allChildrenPruned
}

// InitContainer initialises the container cname of the GoStruct s, it can be
Expand Down
64 changes: 60 additions & 4 deletions ygot/struct_validation_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,25 +609,35 @@ func TestBuildEmptyTree(t *testing.T) {
}

type emptyBranchTestOne struct {
String *string
Struct *emptyBranchTestOneChild
String *string
Struct *emptyBranchTestOneChild
StructMap map[string]*emptyBranchTestOneChild
}

func (*emptyBranchTestOne) IsYANGGoStruct() {}

type emptyBranchTestOneChild struct {
String *string
Struct *emptyBranchTestOneGrandchild
String *string
Enumerated int64
Struct *emptyBranchTestOneGrandchild
}

func (*emptyBranchTestOneChild) IsYANGGoStruct() {}

type emptyBranchTestOneGrandchild struct {
String *string
Slice []string
Struct *emptyBranchTestOneGreatGrandchild
}

func (*emptyBranchTestOneGrandchild) IsYANGGoStruct() {}

type emptyBranchTestOneGreatGrandchild struct {
String *string
}

func (*emptyBranchTestOneGreatGrandchild) IsYANGGoStruct() {}

func TestPruneEmptyBranches(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -689,6 +699,52 @@ func TestPruneEmptyBranches(t *testing.T) {
},
},
},
}, {
name: "struct with unpopulated child and grandchild",
inStruct: &emptyBranchTestOne{
Struct: &emptyBranchTestOneChild{
Struct: &emptyBranchTestOneGrandchild{},
},
},
want: &emptyBranchTestOne{},
}, {
name: "struct with map with unpopulated children",
inStruct: &emptyBranchTestOne{
StructMap: map[string]*emptyBranchTestOneChild{
"value": {
String: String("value"),
Struct: &emptyBranchTestOneGrandchild{
Struct: &emptyBranchTestOneGreatGrandchild{},
},
},
},
},
want: &emptyBranchTestOne{
StructMap: map[string]*emptyBranchTestOneChild{
"value": {
String: String("value"),
},
},
},
}, {
name: "struct with slice, and enumerated value",
inStruct: &emptyBranchTestOne{
Struct: &emptyBranchTestOneChild{
Enumerated: 42,
Struct: &emptyBranchTestOneGrandchild{
Slice: []string{"one", "two"},
Struct: &emptyBranchTestOneGreatGrandchild{},
},
},
},
want: &emptyBranchTestOne{
Struct: &emptyBranchTestOneChild{
Enumerated: 42,
Struct: &emptyBranchTestOneGrandchild{
Slice: []string{"one", "two"},
},
},
},
}}

for _, tt := range tests {
Expand Down

0 comments on commit 2ef38fa

Please sign in to comment.