Skip to content

Commit

Permalink
Merge pull request #130 from hslatman/multiple-base-identities-1.1-v2
Browse files Browse the repository at this point in the history
Add support for multiple `base` substatements in `identity` statement
  • Loading branch information
wenovus authored Oct 2, 2020
2 parents e87239b + b1cab10 commit 22e20cc
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 50 deletions.
18 changes: 10 additions & 8 deletions pkg/yang/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,18 +168,20 @@ func (ms *Modules) resolveIdentities() []error {
// that have a base, so that we can do inheritance of these later.
for _, i := range identities.dict {
if i.Identity.Base != nil {
// This identity inherits from another identity.
// This identity inherits from one or more other identities.

root := RootNode(i.Identity)
base, baseErr := root.findIdentityBase(i.Identity.Base.asString())
for _, b := range i.Identity.Base {
base, baseErr := root.findIdentityBase(b.asString())

if baseErr != nil {
errs = append(errs, baseErr...)
continue
}
if baseErr != nil {
errs = append(errs, baseErr...)
continue
}

// Append this value to the children of the base identity.
base.Identity.Values = append(base.Identity.Values, i.Identity)
// Append this value to the children of the base identity.
base.Identity.Values = append(base.Identity.Values, i.Identity)
}
}
}

Expand Down
119 changes: 78 additions & 41 deletions pkg/yang/identity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package yang
import (
"reflect"
"testing"

"github.com/google/go-cmp/cmp"
)

// inputModule is a mock input YANG module.
Expand All @@ -33,10 +35,10 @@ type idrefOut struct {

// identityOut is the output for a particular identity within the test case.
type identityOut struct {
module string // The module that the identity is within.
name string // The name of the identity.
baseName string // The base of the identity as a string.
values []string // The string names of derived identities.
module string // The module that the identity is within.
name string // The name of the identity.
baseNames []string // The base(s) of the identity as string(s).
values []string // The string names of derived identities.
}

// identityTestCase is a test case for a module which contains identities.
Expand All @@ -48,6 +50,15 @@ type identityTestCase struct {
err string // Test case error string
}

// getBaseNamesFrom is a utility function for getting the base name(s) of an identity
func getBaseNamesFrom(i *Identity) []string {
baseNames := []string{}
for _, base := range i.Base {
baseNames = append(baseNames, base.Name)
}
return baseNames
}

// Test cases for basic identity extraction.
var basicTestCases = []identityTestCase{
{
Expand Down Expand Up @@ -90,10 +101,36 @@ var basicTestCases = []identityTestCase{
identities: []identityOut{
{module: "idtest-two", name: "TEST_ID"},
{module: "idtest-two", name: "TEST_ID_TWO"},
{module: "idtest-two", name: "TEST_CHILD", baseName: "TEST_ID"},
{module: "idtest-two", name: "TEST_CHILD", baseNames: []string{"TEST_ID"}},
},
err: "basic-test-case-2: could not resolve identities",
},
{
name: "basic-test-case-3: Check identity with multiple bases.",
in: []inputModule{
{
name: "idtest-three",
content: `
module idtest-three {
namespace "urn:idthree";
prefix "idthree";
identity BASE_ONE;
identity BASE_TWO;
identity TEST_CHILD_WITH_MULTIPLE_BASES {
base BASE_ONE;
base BASE_TWO;
}
}
`},
},
identities: []identityOut{
{module: "idtest-three", name: "BASE_ONE"},
{module: "idtest-three", name: "BASE_TWO"},
{module: "idtest-three", name: "TEST_CHILD_WITH_MULTIPLE_BASES", baseNames: []string{"BASE_ONE", "BASE_TWO"}},
},
err: "basic-test-case-3: could not resolve identities",
},
}

// Test the ability to extract identities from a module with the correct base
Expand Down Expand Up @@ -127,15 +164,15 @@ func TestIdentityExtract(t *testing.T) {
t.Errorf("Could not found identity %s in %s", ti.name, ti.module)
}

if ti.baseName != "" {
if ti.baseName != thisID.Base.Name {
t.Errorf("Identity %s did not have expected base %s, had %s", ti.name,
ti.baseName, thisID.Base.Name)
actualBaseNames := getBaseNamesFrom(thisID)
if len(ti.baseNames) > 0 {
if diff := cmp.Diff(actualBaseNames, ti.baseNames); diff != "" {
t.Errorf("(-got, +want):\n%s", diff)
}
} else {
if thisID.Base != nil {
t.Errorf("Identity %s had an unexpected base %s", thisID.Name,
thisID.Base.Name)
t.Errorf("Identity %s had unexpected base(s) %s", thisID.Name,
actualBaseNames)
}
}
}
Expand Down Expand Up @@ -179,9 +216,9 @@ var treeTestCases = []identityTestCase{
values: []string{"LOCAL_REMOTE_BASE"},
},
{
module: "base",
name: "LOCAL_REMOTE_BASE",
baseName: "r:REMOTE_BASE",
module: "base",
name: "LOCAL_REMOTE_BASE",
baseNames: []string{"r:REMOTE_BASE"},
},
},
},
Expand Down Expand Up @@ -231,31 +268,31 @@ var treeTestCases = []identityTestCase{
},
},
{
module: "base",
name: "GRANDFATHER",
baseName: "GREATGRANDFATHER",
values: []string{"FATHER", "UNCLE", "SON", "BROTHER"},
module: "base",
name: "GRANDFATHER",
baseNames: []string{"GREATGRANDFATHER"},
values: []string{"FATHER", "UNCLE", "SON", "BROTHER"},
},
{
module: "base",
name: "GREATUNCLE",
baseName: "GREATGRANDFATHER",
module: "base",
name: "GREATUNCLE",
baseNames: []string{"GREATGRANDFATHER"},
},
{
module: "base",
name: "FATHER",
baseName: "GRANDFATHER",
values: []string{"SON", "BROTHER"},
module: "base",
name: "FATHER",
baseNames: []string{"GRANDFATHER"},
values: []string{"SON", "BROTHER"},
},
{
module: "base",
name: "UNCLE",
baseName: "GRANDFATHER",
module: "base",
name: "UNCLE",
baseNames: []string{"GRANDFATHER"},
},
{
module: "base",
name: "BROTHER",
baseName: "FATHER",
module: "base",
name: "BROTHER",
baseNames: []string{"FATHER"},
},
},
},
Expand Down Expand Up @@ -288,9 +325,9 @@ var treeTestCases = []identityTestCase{
values: []string{"NOTBASE"},
},
{
module: "base",
name: "NOTBASE",
baseName: "BASE",
module: "base",
name: "NOTBASE",
baseNames: []string{"BASE"},
},
},
idrefs: []idrefOut{
Expand Down Expand Up @@ -334,9 +371,9 @@ var treeTestCases = []identityTestCase{
values: []string{"CHILD4"},
},
{
module: "base4",
name: "CHILD4",
baseName: "BASE4",
module: "base4",
name: "CHILD4",
baseNames: []string{"BASE4"},
},
},
idrefs: []idrefOut{
Expand Down Expand Up @@ -438,10 +475,10 @@ func TestIdentityTree(t *testing.T) {
chkID.module)
}

if chkID.baseName != "" {
if chkID.baseName != foundID.Base.Name {
t.Errorf("Couldn't find base %s for ID %s", chkID.baseName,
foundID.Base.Name)
if len(chkID.baseNames) > 0 {
actualBaseNames := getBaseNamesFrom(foundID)
if diff := cmp.Diff(actualBaseNames, chkID.baseNames); diff != "" {
t.Errorf("(-got, +want):\n%s", diff)
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/yang/yang.go
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ type Identity struct {
Parent Node `yang:"Parent,nomerge" json:"-"`
Extensions []*Statement `yang:"Ext" json:"-"`

Base *Value `yang:"base" json:"-"`
Base []*Value `yang:"base" json:"-"`
Description *Value `yang:"description" json:"-"`
IfFeature []*Value `yang:"if-feature" json:"-"`
Reference *Value `yang:"reference" json:"-"`
Expand Down

0 comments on commit 22e20cc

Please sign in to comment.