Skip to content

Commit

Permalink
Add OrderedByUser field (#242)
Browse files Browse the repository at this point in the history
* Add `OrderedByUser` field

* unit tests

* add negative test

* rename test
  • Loading branch information
wenovus authored Apr 25, 2023
1 parent fc70dac commit 9a319ef
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 8 deletions.
34 changes: 31 additions & 3 deletions pkg/yang/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,31 @@ type RPCEntry struct {
type ListAttr struct {
MinElements uint64 // leaf-list or list MUST have at least min-elements
MaxElements uint64 // leaf-list or list has at most max-elements
OrderedBy *Value // order of entries determined by "system" or "user"
// OrderedBy is deprecated. Use OrderedByUser instead.
OrderedBy *Value
// OrderedByUser indicates whether the entries are "ordered-by user".
// Otherwise the order is determined by the system.
OrderedByUser bool
}

// parseOrderedBy parses the ordered-by value and classifies the list/leaf-list
// by whether the `ordered-by user` modifier is active.
//
// For more information see
// https://datatracker.ietf.org/doc/html/rfc7950#section-7.7.7
func (l *ListAttr) parseOrderedBy(s *Value) error {
if s == nil {
return nil
}
l.OrderedBy = s
switch s.Name {
case "user":
l.OrderedByUser = true
case "system":
default:
return fmt.Errorf("%s: ordered-by has invalid argument: %q", Source(s), s.Name)
}
return nil
}

// NewDefaultListAttr returns a new ListAttr object with min/max elements being
Expand Down Expand Up @@ -610,7 +634,9 @@ func ToEntry(n Node) (e *Entry) {

e = ToEntry(leaf)
e.ListAttr = NewDefaultListAttr()
e.ListAttr.OrderedBy = s.OrderedBy
if err := e.ListAttr.parseOrderedBy(s.OrderedBy); err != nil {
e.addError(err)
}
var err error
if e.ListAttr.MaxElements, err = semCheckMaxElements(s.MaxElements); err != nil {
e.addError(err)
Expand Down Expand Up @@ -647,7 +673,9 @@ func ToEntry(n Node) (e *Entry) {
switch s := n.(type) {
case *List:
e.ListAttr = NewDefaultListAttr()
e.ListAttr.OrderedBy = s.OrderedBy
if err := e.ListAttr.parseOrderedBy(s.OrderedBy); err != nil {
e.addError(err)
}
var err error
if e.ListAttr.MaxElements, err = semCheckMaxElements(s.MaxElements); err != nil {
e.addError(err)
Expand Down
162 changes: 162 additions & 0 deletions pkg/yang/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3958,3 +3958,165 @@ func TestLess(t *testing.T) {
}
}
}

type customTestCases struct {
wantEntryPath string
wantEntryCustomTest func(t *testing.T, e *Entry)
}

func TestOrderedBy(t *testing.T) {
tests := []struct {
name string
inModules map[string]string
testcases []customTestCases
wantErrSubstr string
}{{
name: "ordered-by user",
inModules: map[string]string{
"test.yang": `
module test {
prefix "t";
namespace "urn:t";
list ordered-list {
key "name";
ordered-by user;
leaf name {
type string;
}
}
list unordered-list {
key "name";
ordered-by system;
leaf name {
type string;
}
}
list unordered-list2 {
key "name";
leaf name {
type string;
}
}
leaf-list ordered-leaflist {
ordered-by user;
type string;
}
leaf-list unordered-leaflist {
ordered-by system;
type string;
}
leaf-list unordered-leaflist2 {
type string;
}
}
`,
},
testcases: []customTestCases{{
wantEntryPath: "/test/ordered-list",
wantEntryCustomTest: func(t *testing.T, e *Entry) {
if got, want := e.ListAttr.OrderedByUser, true; got != want {
t.Errorf("got %v, want %v", got, want)
}
},
}, {
wantEntryPath: "/test/unordered-list",
wantEntryCustomTest: func(t *testing.T, e *Entry) {
if got, want := e.ListAttr.OrderedByUser, false; got != want {
t.Errorf("got %v, want %v", got, want)
}
},
}, {
wantEntryPath: "/test/unordered-list2",
wantEntryCustomTest: func(t *testing.T, e *Entry) {
if got, want := e.ListAttr.OrderedByUser, false; got != want {
t.Errorf("got %v, want %v", got, want)
}
},
}, {
wantEntryPath: "/test/ordered-leaflist",
wantEntryCustomTest: func(t *testing.T, e *Entry) {
if got, want := e.ListAttr.OrderedByUser, true; got != want {
t.Errorf("got %v, want %v", got, want)
}
},
}, {
wantEntryPath: "/test/unordered-leaflist",
wantEntryCustomTest: func(t *testing.T, e *Entry) {
if got, want := e.ListAttr.OrderedByUser, false; got != want {
t.Errorf("got %v, want %v", got, want)
}
},
}, {
wantEntryPath: "/test/unordered-leaflist2",
wantEntryCustomTest: func(t *testing.T, e *Entry) {
if got, want := e.ListAttr.OrderedByUser, false; got != want {
t.Errorf("got %v, want %v", got, want)
}
},
}},
}, {
name: "ordered-by client: invalid argument",
inModules: map[string]string{
"test.yang": `
module test {
prefix "t";
namespace "urn:t";
list ordered-list {
key "name";
ordered-by client;
leaf name {
type string;
}
}
}
`,
},
wantErrSubstr: "ordered-by has invalid argument",
}}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ms := NewModules()
var errs []error
for n, m := range tt.inModules {
if err := ms.Parse(m, n); err != nil {
errs = append(errs, err)
}
}

if len(errs) > 0 {
t.Fatalf("ms.Parse(), got unexpected error parsing input modules: %v", errs)
}

if errs := ms.Process(); len(errs) > 0 {
if len(errs) == 1 {
if diff := errdiff.Substring(errs[0], tt.wantErrSubstr); diff != "" {
t.Fatalf("did not get expected error, %s", diff)
}
return
}
t.Fatalf("ms.Process(), got too many errors processing entries: %v", errs)
}

dir := map[string]*Entry{}
for _, m := range ms.Modules {
addTreeE(ToEntry(m), dir)
}

for _, tc := range tt.testcases {
e, ok := dir[tc.wantEntryPath]
if !ok {
t.Fatalf("could not find entry %s within the dir: %v", tc.wantEntryPath, dir)
}
tc.wantEntryCustomTest(t, e)
}
})
}
}
15 changes: 10 additions & 5 deletions pkg/yang/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ func TestMarshalJSON(t *testing.T) {
"ListAttr": {
"MinElements": 0,
"MaxElements": 18446744073709551615,
"OrderedBy": null
"OrderedBy": null,
"OrderedByUser": false
}
}
},
Expand All @@ -356,7 +357,8 @@ func TestMarshalJSON(t *testing.T) {
"ListAttr": {
"MinElements": 48,
"MaxElements": 42,
"OrderedBy": null
"OrderedBy": null,
"OrderedByUser": false
},
"Identities": [
{
Expand Down Expand Up @@ -534,7 +536,8 @@ func TestParseAndMarshal(t *testing.T) {
"ListAttr": {
"MinElements": 10,
"MaxElements": 18446744073709551615,
"OrderedBy": null
"OrderedBy": null,
"OrderedByUser": false
}
},
"d": {
Expand Down Expand Up @@ -623,7 +626,8 @@ func TestParseAndMarshal(t *testing.T) {
"ListAttr": {
"MinElements": 0,
"MaxElements": 18446744073709551615,
"OrderedBy": null
"OrderedBy": null,
"OrderedByUser": false
}
},
"zip2": {
Expand All @@ -645,7 +649,8 @@ func TestParseAndMarshal(t *testing.T) {
"ListAttr": {
"MinElements": 0,
"MaxElements": 1000,
"OrderedBy": null
"OrderedBy": null,
"OrderedByUser": false
}
}
}
Expand Down

0 comments on commit 9a319ef

Please sign in to comment.