Repository: openconfig/ygot
Pull request #570 (2021-08-13 02:41:15)

Move findMapPaths to directory.go
This is a `Directory` function that should be in directory.go

coveralls: 
[![Coverage Status](https://coveralls.io/builds/42118707/badge)](https://coveralls.io/builds/42118707)

Coverage remained the same at 90.841% when pulling **f4f0482000b99496f7414f348091473a178b1c80 on move-findmappaths** into **e20748e60b9601a15eb37fbcb73d1f3cdb559c9a on add-generate**.


Patch:
diff --git a/util/path.go b/util/path.go
index 9743ef7..5902894 100644
--- a/util/path.go
+++ b/util/path.go
@@ -104,16 +104,26 @@ func SchemaTreePathNoModule(e *yang.Entry) string {
 // its path, expressed as a slice of strings, which is returned.
 func SchemaPathNoChoiceCase(elem *yang.Entry) []string {
 	var pp []string
+	for _, e := range SchemaEntryPathNoChoiceCase(elem) {
+		pp = append(pp, e.Name)
+	}
+	return pp
+}
+
+// SchemaEntryPathNoChoiceCase takes an input yang.Entry and walks up the tree to find
+// its path, expressed as a slice of Entrys, which is returned.
+func SchemaEntryPathNoChoiceCase(elem *yang.Entry) []*yang.Entry {
+	var pp []*yang.Entry
 	if elem == nil {
 		return pp
 	}
 	e := elem
 	for ; e.Parent != nil; e = e.Parent {
 		if !IsChoiceOrCase(e) {
-			pp = append(pp, e.Name)
+			pp = append(pp, e)
 		}
 	}
-	pp = append(pp, e.Name)
+	pp = append(pp, e)
 
 	// Reverse the slice that was specified to us as it was appended to
 	// from the leaf to the root.
diff --git a/ygen/directory.go b/ygen/directory.go
index 58b29a6..b9ec909 100644
--- a/ygen/directory.go
+++ b/ygen/directory.go
@@ -22,6 +22,7 @@ import (
 	"fmt"
 	"sort"
 
+	"github.com/google/go-cmp/cmp"
 	"github.com/openconfig/goyang/pkg/yang"
 	"github.com/openconfig/ygot/genutil"
 	"github.com/openconfig/ygot/util"
@@ -169,3 +170,68 @@ func findSchemaPath(parent *Directory, fieldName string, shadowSchemaPaths, abso
 	}
 	return fieldSlicePath[len(parent.Path)-1:], nil
 }
+
+// findMapPaths takes an input field name for a parent Directory and calculates the set of schemapaths that it represents.
+// If absolutePaths is set, the paths are absolute otherwise they are relative to the parent. If
+// the input entry is a key to a list, and is of type leafref, then the corresponding target leaf's
+// path is also returned. If shadowSchemaPaths is set, then the path of the
+// field deprioritized via compression is returned instead of the prioritized paths.
+// The first returned path is the path of the direct child, with the shadow
+// child's path afterwards, and the key leafref, if any, last.
+func findMapPaths(parent *Directory, fieldName string, compressPaths, shadowSchemaPaths, absolutePaths bool) ([][]string, error) {
+	childPath, err := findSchemaPath(parent, fieldName, shadowSchemaPaths, absolutePaths)
+	if err != nil {
+		return nil, err
+	}
+	var mapPaths [][]string
+	if childPath != nil {
+		mapPaths = append(mapPaths, childPath)
+	}
+	// Only for compressed data schema paths for list fields do we have the
+	// possibility for a direct leafref path as a second path for the field.
+	if !compressPaths || parent.ListAttr == nil {
+		return mapPaths, nil
+	}
+
+	field, ok := parent.Fields[fieldName]
+	if !ok {
+		return nil, fmt.Errorf("field name %s does not exist in Directory %s", fieldName, parent.Path)
+	}
+	fieldSlicePath := util.SchemaPathNoChoiceCase(field)
+
+	// Handle specific issue of compressed path schemas, where a key of the
+	// parent list is a leafref to this leaf.
+	for _, k := range parent.ListAttr.KeyElems {
+		// If the key element has the same path as this element, and the
+		// corresponding element that is within the parent's container is of
+		// type leafref, then within an OpenConfig schema this means that
+		// the key leaf was a pointer to this leaf. To this end, we set
+		// isKey to true so that the struct field can be mapped to the
+		// leafref leaf within the schema as well as the target of the
+		// leafref.
+		if k.Parent == nil || k.Parent.Parent == nil || k.Parent.Parent.Dir[k.Name] == nil || k.Parent.Parent.Dir[k.Name].Type == nil {
+			return nil, fmt.Errorf("invalid compressed schema, could not find the key %s or the grandparent of %s", k.Name, k.Path())
+		}
+
+		// If a key of the list is a leafref that points to the field,
+		// then add this as an alternative path.
+		// Note: if k is a leafref, buildListKey() would have already
+		// resolved it the field that the leafref points to. So, we
+		// compare their absolute paths for equality.
+		if k.Parent.Parent.Dir[k.Name].Type.Kind == yang.Yleafref && cmp.Equal(util.SchemaPathNoChoiceCase(k), fieldSlicePath) {
+			// The path of the key element is simply the name of the leaf under the
+			// list, since the YANG specification enforces that keys are direct
+			// children of the list.
+			keyPath := []string{fieldSlicePath[len(fieldSlicePath)-1]}
+			if absolutePaths {
+				// If absolute paths are required, then the 'config' or 'state' container needs to be omitted from
+				// the complete path for the secondary mapping.
+				keyPath = append([]string{""}, fieldSlicePath[1:len(fieldSlicePath)-2]...)
+				keyPath = append(keyPath, fieldSlicePath[len(fieldSlicePath)-1])
+			}
+			mapPaths = append(mapPaths, keyPath)
+			break
+		}
+	}
+	return mapPaths, nil
+}
diff --git a/ygen/gogen.go b/ygen/gogen.go
index 0d62c61..22c36a4 100644
--- a/ygen/gogen.go
+++ b/ygen/gogen.go
@@ -22,7 +22,6 @@ import (
 	"text/template"
 
 	log "github.com/golang/glog"
-	"github.com/google/go-cmp/cmp"
 
 	"github.com/openconfig/gnmi/errlist"
 	gpb "github.com/openconfig/gnmi/proto/gnmi"
@@ -2114,72 +2113,6 @@ func writeGoEnum(inputEnum *yangEnum) (goEnumCodeSnippet, error) {
 	}, err
 }
 
-// findMapPaths takes an input field name for a parent Directory and calculates the set of schemapaths that it represents.
-// If absolutePaths is set, the paths are absolute otherwise they are relative to the parent. If
-// the input entry is a key to a list, and is of type leafref, then the corresponding target leaf's
-// path is also returned. If shadowSchemaPaths is set, then the path of the
-// field deprioritized via compression is returned instead of the prioritized paths.
-// The first returned path is the path of the direct child, with the shadow
-// child's path afterwards, and the key leafref, if any, last.
-// TODO(wenbli): This is used by both Go and proto generation, it should be moved to genstate.go or genutil.
-func findMapPaths(parent *Directory, fieldName string, compressPaths, shadowSchemaPaths, absolutePaths bool) ([][]string, error) {
-	childPath, err := findSchemaPath(parent, fieldName, shadowSchemaPaths, absolutePaths)
-	if err != nil {
-		return nil, err
-	}
-	var mapPaths [][]string
-	if childPath != nil {
-		mapPaths = append(mapPaths, childPath)
-	}
-	// Only for compressed data schema paths for list fields do we have the
-	// possibility for a direct leafref path as a second path for the field.
-	if !compressPaths || parent.ListAttr == nil {
-		return mapPaths, nil
-	}
-
-	field, ok := parent.Fields[fieldName]
-	if !ok {
-		return nil, fmt.Errorf("field name %s does not exist in Directory %s", fieldName, parent.Path)
-	}
-	fieldSlicePath := util.SchemaPathNoChoiceCase(field)
-
-	// Handle specific issue of compressed path schemas, where a key of the
-	// parent list is a leafref to this leaf.
-	for _, k := range parent.ListAttr.KeyElems {
-		// If the key element has the same path as this element, and the
-		// corresponding element that is within the parent's container is of
-		// type leafref, then within an OpenConfig schema this means that
-		// the key leaf was a pointer to this leaf. To this end, we set
-		// isKey to true so that the struct field can be mapped to the
-		// leafref leaf within the schema as well as the target of the
-		// leafref.
-		if k.Parent == nil || k.Parent.Parent == nil || k.Parent.Parent.Dir[k.Name] == nil || k.Parent.Parent.Dir[k.Name].Type == nil {
-			return nil, fmt.Errorf("invalid compressed schema, could not find the key %s or the grandparent of %s", k.Name, k.Path())
-		}
-
-		// If a key of the list is a leafref that points to the field,
-		// then add this as an alternative path.
-		// Note: if k is a leafref, buildListKey() would have already
-		// resolved it the field that the leafref points to. So, we
-		// compare their absolute paths for equality.
-		if k.Parent.Parent.Dir[k.Name].Type.Kind == yang.Yleafref && cmp.Equal(util.SchemaPathNoChoiceCase(k), fieldSlicePath) {
-			// The path of the key element is simply the name of the leaf under the
-			// list, since the YANG specification enforces that keys are direct
-			// children of the list.
-			keyPath := []string{fieldSlicePath[len(fieldSlicePath)-1]}
-			if absolutePaths {
-				// If absolute paths are required, then the 'config' or 'state' container needs to be omitted from
-				// the complete path for the secondary mapping.
-				keyPath = append([]string{""}, fieldSlicePath[1:len(fieldSlicePath)-2]...)
-				keyPath = append(keyPath, fieldSlicePath[len(fieldSlicePath)-1])
-			}
-			mapPaths = append(mapPaths, keyPath)
-			break
-		}
-	}
-	return mapPaths, nil
-}
-
 // generateEnumMap outputs a map from the enumMapTemplate. It takes an input of
 // a map corresponding to the enumerated types that are defined in the input YANG
 // schema, keyed by their generating Go name. The values of the map for each key is


Test patch:
diff --git a/util/path_test.go b/util/path_test.go
index 78ad51f..dab0042 100644
--- a/util/path_test.go
+++ b/util/path_test.go
@@ -359,6 +359,50 @@ func TestSchemaPathNoChoiceCase(t *testing.T) {
 	}
 }
 
+func TestSchemaEntryPathNoChoiceCase(t *testing.T) {
+	containerWithChoiceSchema := getContainerWithChoiceSchema()
+
+	tests := []struct {
+		desc  string
+		entry *yang.Entry
+		want  []*yang.Entry
+	}{
+		{
+			desc:  "nil entry",
+			entry: nil,
+			want:  nil,
+		},
+		{
+			desc:  "choice entry",
+			entry: containerWithChoiceSchema.Dir["choice1"],
+			want:  []*yang.Entry{containerWithChoiceSchema},
+		},
+		{
+			desc:  "case entry",
+			entry: containerWithChoiceSchema.Dir["choice1"].Dir["case1"],
+			want:  []*yang.Entry{containerWithChoiceSchema},
+		},
+		{
+			desc:  "case1-leaf1",
+			entry: containerWithChoiceSchema.Dir["choice1"].Dir["case1"].Dir["case1-leaf1"],
+			want:  []*yang.Entry{containerWithChoiceSchema, containerWithChoiceSchema.Dir["choice1"].Dir["case1"].Dir["case1-leaf1"]},
+		},
+		{
+			desc:  "case21-leaf",
+			entry: containerWithChoiceSchema.Dir["choice1"].Dir["case2"].Dir["case2_choice1"].Dir["case21"].Dir["case21-leaf"],
+			want:  []*yang.Entry{containerWithChoiceSchema, containerWithChoiceSchema.Dir["choice1"].Dir["case2"].Dir["case2_choice1"].Dir["case21"].Dir["case21-leaf"]},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.desc, func(t *testing.T) {
+			if got, want := SchemaEntryPathNoChoiceCase(tt.entry), tt.want; !reflect.DeepEqual(got, want) {
+				t.Errorf("got:\n%v\nwant:\n%v\n", got, want)
+			}
+		})
+	}
+}
+
 func TestRemoveXPATHPredicates(t *testing.T) {
 	tests := []struct {
 		desc    string
diff --git a/ygen/directory_test.go b/ygen/directory_test.go
index 23b1baa..c91b624 100644
--- a/ygen/directory_test.go
+++ b/ygen/directory_test.go
@@ -399,3 +399,360 @@ func TestFindSchemaPath(t *testing.T) {
 		})
 	}
 }
+
+// TestFindMapPaths ensures that the schema paths that an entity should be
+// mapped to are properly extracted from a schema element.
+func TestFindMapPaths(t *testing.T) {
+	tests := []struct {
+		name                string
+		inStruct            *Directory
+		inField             string
+		inCompressPaths     bool
+		inShadowSchemaPaths bool
+		inAbsolutePaths     bool
+		wantPaths           [][]string
+		wantErr             bool
+	}{{
+		name: "first-level container with path compression off",
+		inStruct: &Directory{
+			Name: "AContainer",
+			Path: []string{"", "a-module", "a-container"},
+			Fields: map[string]*yang.Entry{
+				"field-a": {
+					Name: "field-a",
+					Parent: &yang.Entry{
+						Name: "a-container",
+						Parent: &yang.Entry{
+							Name: "a-module",
+						},
+					},
+				},
+			},
+		},
+		inField:   "field-a",
+		wantPaths: [][]string{{"field-a"}},
+	}, {
+		name: "invalid parent path - shorter than directory path",
+		inStruct: &Directory{
+			Name: "AContainer",
+			Path: []string{"", "a-module", "a-container"},
+			Fields: map[string]*yang.Entry{
+				"field-q": {
+					Name: "field-q",
+					Parent: &yang.Entry{
+						Name: "q-container",
+					},
+				},
+			},
+		},
+		inField: "field-q",
+		wantErr: true,
+	}, {
+		name: "first-level container with path compression on",
+		inStruct: &Directory{
+			Name: "BContainer",
+			Path: []string{"", "a-module", "b-container"},
+			Fields: map[string]*yang.Entry{
+				"field-b": {
+					Name: "field-b",
+					Parent: &yang.Entry{
+						Name: "config",
+						Parent: &yang.Entry{
+							Name: "b-container",
+							Parent: &yang.Entry{
+								Name: "a-module",
+							},
+						},
+					},
+				},
+			},
+			ShadowedFields: map[string]*yang.Entry{
+				"field-b": {
+					Name: "field-b",
+					Parent: &yang.Entry{
+						Name: "state",
+						Parent: &yang.Entry{
+							Name: "b-container",
+							Parent: &yang.Entry{
+								Name: "a-module",
+							},
+						},
+					},
+				},
+			},
+		},
+		inField:         "field-b",
+		inCompressPaths: true,
+		wantPaths:       [][]string{{"config", "field-b"}},
+	}, {
+		name: "first-level container with path compression on and ignoreShadowSchemaPaths on",
+		inStruct: &Directory{
+			Name: "BContainer",
+			Path: []string{"", "a-module", "b-container"},
+			Fields: map[string]*yang.Entry{
+				"field-b": {
+					Name: "field-b",
+					Parent: &yang.Entry{
+						Name: "config",
+						Parent: &yang.Entry{
+							Name: "b-container",
+							Parent: &yang.Entry{
+								Name: "a-module",
+							},
+						},
+					},
+				},
+			},
+			ShadowedFields: map[string]*yang.Entry{
+				"field-b": {
+					Name: "field-b",
+					Parent: &yang.Entry{
+						Name: "state",
+						Parent: &yang.Entry{
+							Name: "b-container",
+							Parent: &yang.Entry{
+								Name: "a-module",
+							},
+						},
+					},
+				},
+			},
+		},
+		inField:             "field-b",
+		inCompressPaths:     true,
+		inShadowSchemaPaths: true,
+		wantPaths:           [][]string{{"state", "field-b"}},
+	}, {
+		name: "container with absolute paths on",
+		inStruct: &Directory{
+			Name: "BContainer",
+			Path: []string{"", "a-module", "b-container", "c-container"},
+			Fields: map[string]*yang.Entry{
+				"field-d": {
+					Name: "field-d",
+					Parent: &yang.Entry{
+						Name: "c-container",
+						Parent: &yang.Entry{
+							Name: "b-container",
+							Parent: &yang.Entry{
+								Name: "a-module",
+							},
+						},
+					},
+				},
+			},
+		},
+		inField:         "field-d",
+		inAbsolutePaths: true,
+		wantPaths:       [][]string{{"", "b-container", "c-container", "field-d"}},
+	}, {
+		name: "top-level module - not valid to map",
+		inStruct: &Directory{
+			Name:   "CContainer",
+			Path:   []string{"", "c-container"}, // Does not have a valid module.
+			Fields: map[string]*yang.Entry{"top": {}},
+		},
+		inField: "top",
+		wantErr: true,
+	}, {
+		name: "list with leafref key",
+		inStruct: &Directory{
+			Name: "DList",
+			Path: []string{"", "d-module", "d-container", "d-list"},
+			ListAttr: &YangListAttr{
+				KeyElems: []*yang.Entry{
+					{
+						Name: "d-key",
+						Type: &yang.YangType{
+							Kind: yang.Yleafref,
+						},
+						Parent: &yang.Entry{
+							Name: "config",
+							Parent: &yang.Entry{
+								Name: "d-list",
+								Kind: yang.DirectoryEntry,
+								Dir: map[string]*yang.Entry{
+									"d-key": {
+										Name: "d-key",
+										Type: &yang.YangType{Kind: yang.Yleafref},
+									},
+								},
+								Parent: &yang.Entry{
+									Name: "d-container",
+									Parent: &yang.Entry{
+										Name: "d-module",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			Fields: map[string]*yang.Entry{
+				"d-key": {
+					Name: "d-key",
+					Type: &yang.YangType{
+						Kind: yang.Yleafref,
+					},
+					Parent: &yang.Entry{
+						Name: "config",
+						Parent: &yang.Entry{
+							Name: "d-list",
+							Kind: yang.DirectoryEntry,
+							Dir: map[string]*yang.Entry{
+								"d-key": {
+									Name: "d-key",
+									Type: &yang.YangType{Kind: yang.Yleafref},
+								},
+							},
+							Parent: &yang.Entry{
+								Name: "d-container",
+								Parent: &yang.Entry{
+									Name: "d-module",
+								},
+							},
+						},
+					},
+				},
+			},
+			ShadowedFields: map[string]*yang.Entry{
+				"d-key": {
+					Name: "d-key",
+					Parent: &yang.Entry{
+						Name: "state",
+						Parent: &yang.Entry{
+							Name: "d-list",
+							Kind: yang.DirectoryEntry,
+							Dir: map[string]*yang.Entry{
+								"d-key": {
+									Name: "d-key",
+									Type: &yang.YangType{Kind: yang.Yleafref},
+								},
+							},
+							Parent: &yang.Entry{
+								Name: "d-container",
+								Parent: &yang.Entry{
+									Name: "d-module",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		inField:         "d-key",
+		inCompressPaths: true,
+		wantPaths: [][]string{
+			{"config", "d-key"},
+			{"d-key"},
+		},
+	}, {
+		name: "list with leafref key with shadowSchemaPaths=true",
+		inStruct: &Directory{
+			Name: "DList",
+			Path: []string{"", "d-module", "d-container", "d-list"},
+			ListAttr: &YangListAttr{
+				KeyElems: []*yang.Entry{
+					{
+						Name: "d-key",
+						Type: &yang.YangType{
+							Kind: yang.Yleafref,
+						},
+						Parent: &yang.Entry{
+							Name: "config",
+							Parent: &yang.Entry{
+								Name: "d-list",
+								Kind: yang.DirectoryEntry,
+								Dir: map[string]*yang.Entry{
+									"d-key": {
+										Name: "d-key",
+										Type: &yang.YangType{Kind: yang.Yleafref},
+									},
+								},
+								Parent: &yang.Entry{
+									Name: "d-container",
+									Parent: &yang.Entry{
+										Name: "d-module",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			Fields: map[string]*yang.Entry{
+				"d-key": {
+					Name: "d-key",
+					Type: &yang.YangType{
+						Kind: yang.Yleafref,
+					},
+					Parent: &yang.Entry{
+						Name: "config",
+						Parent: &yang.Entry{
+							Name: "d-list",
+							Kind: yang.DirectoryEntry,
+							Dir: map[string]*yang.Entry{
+								"d-key": {
+									Name: "d-key",
+									Type: &yang.YangType{Kind: yang.Yleafref},
+								},
+							},
+							Parent: &yang.Entry{
+								Name: "d-container",
+								Parent: &yang.Entry{
+									Name: "d-module",
+								},
+							},
+						},
+					},
+				},
+			},
+			ShadowedFields: map[string]*yang.Entry{
+				"d-key": {
+					Name: "d-key",
+					Parent: &yang.Entry{
+						Name: "state",
+						Parent: &yang.Entry{
+							Name: "d-list",
+							Kind: yang.DirectoryEntry,
+							Dir: map[string]*yang.Entry{
+								"d-key": {
+									Name: "d-key",
+									Type: &yang.YangType{Kind: yang.Yleafref},
+								},
+							},
+							Parent: &yang.Entry{
+								Name: "d-container",
+								Parent: &yang.Entry{
+									Name: "d-module",
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		inField:             "d-key",
+		inCompressPaths:     true,
+		inShadowSchemaPaths: true,
+		wantPaths: [][]string{
+			{"state", "d-key"},
+			{"d-key"},
+		},
+	}}
+
+	for _, tt := range tests {
+		got, err := findMapPaths(tt.inStruct, tt.inField, tt.inCompressPaths, tt.inShadowSchemaPaths, tt.inAbsolutePaths)
+		if err != nil {
+			if !tt.wantErr {
+				t.Errorf("%s: YANGCodeGenerator.findMapPaths(%v, %v): compress: %v, shadowSchemaPaths: %v, got unexpected error: %v",
+					tt.name, tt.inStruct, tt.inField, tt.inCompressPaths, tt.inShadowSchemaPaths, err)
+			}
+			continue
+		}
+
+		if diff := cmp.Diff(tt.wantPaths, got); diff != "" {
+			t.Errorf("%s: YANGCodeGenerator.findMapPaths(%v, %v): compress: %v, shadowSchemaPaths: %v, (-want, +got):\n%s", tt.name, tt.inStruct, tt.inField, tt.inCompressPaths, tt.inShadowSchemaPaths, diff)
+		}
+	}
+}
diff --git a/ygen/gogen_test.go b/ygen/gogen_test.go
index c25e1bf..6289fa6 100644
--- a/ygen/gogen_test.go
+++ b/ygen/gogen_test.go
@@ -1982,363 +1982,6 @@ const (
 	}
 }
 
-// TestFindMapPaths ensures that the schema paths that an entity should be
-// mapped to are properly extracted from a schema element.
-func TestFindMapPaths(t *testing.T) {
-	tests := []struct {
-		name                string
-		inStruct            *Directory
-		inField             string
-		inCompressPaths     bool
-		inShadowSchemaPaths bool
-		inAbsolutePaths     bool
-		wantPaths           [][]string
-		wantErr             bool
-	}{{
-		name: "first-level container with path compression off",
-		inStruct: &Directory{
-			Name: "AContainer",
-			Path: []string{"", "a-module", "a-container"},
-			Fields: map[string]*yang.Entry{
-				"field-a": {
-					Name: "field-a",
-					Parent: &yang.Entry{
-						Name: "a-container",
-						Parent: &yang.Entry{
-							Name: "a-module",
-						},
-					},
-				},
-			},
-		},
-		inField:   "field-a",
-		wantPaths: [][]string{{"field-a"}},
-	}, {
-		name: "invalid parent path - shorter than directory path",
-		inStruct: &Directory{
-			Name: "AContainer",
-			Path: []string{"", "a-module", "a-container"},
-			Fields: map[string]*yang.Entry{
-				"field-q": {
-					Name: "field-q",
-					Parent: &yang.Entry{
-						Name: "q-container",
-					},
-				},
-			},
-		},
-		inField: "field-q",
-		wantErr: true,
-	}, {
-		name: "first-level container with path compression on",
-		inStruct: &Directory{
-			Name: "BContainer",
-			Path: []string{"", "a-module", "b-container"},
-			Fields: map[string]*yang.Entry{
-				"field-b": {
-					Name: "field-b",
-					Parent: &yang.Entry{
-						Name: "config",
-						Parent: &yang.Entry{
-							Name: "b-container",
-							Parent: &yang.Entry{
-								Name: "a-module",
-							},
-						},
-					},
-				},
-			},
-			ShadowedFields: map[string]*yang.Entry{
-				"field-b": {
-					Name: "field-b",
-					Parent: &yang.Entry{
-						Name: "state",
-						Parent: &yang.Entry{
-							Name: "b-container",
-							Parent: &yang.Entry{
-								Name: "a-module",
-							},
-						},
-					},
-				},
-			},
-		},
-		inField:         "field-b",
-		inCompressPaths: true,
-		wantPaths:       [][]string{{"config", "field-b"}},
-	}, {
-		name: "first-level container with path compression on and ignoreShadowSchemaPaths on",
-		inStruct: &Directory{
-			Name: "BContainer",
-			Path: []string{"", "a-module", "b-container"},
-			Fields: map[string]*yang.Entry{
-				"field-b": {
-					Name: "field-b",
-					Parent: &yang.Entry{
-						Name: "config",
-						Parent: &yang.Entry{
-							Name: "b-container",
-							Parent: &yang.Entry{
-								Name: "a-module",
-							},
-						},
-					},
-				},
-			},
-			ShadowedFields: map[string]*yang.Entry{
-				"field-b": {
-					Name: "field-b",
-					Parent: &yang.Entry{
-						Name: "state",
-						Parent: &yang.Entry{
-							Name: "b-container",
-							Parent: &yang.Entry{
-								Name: "a-module",
-							},
-						},
-					},
-				},
-			},
-		},
-		inField:             "field-b",
-		inCompressPaths:     true,
-		inShadowSchemaPaths: true,
-		wantPaths:           [][]string{{"state", "field-b"}},
-	}, {
-		name: "container with absolute paths on",
-		inStruct: &Directory{
-			Name: "BContainer",
-			Path: []string{"", "a-module", "b-container", "c-container"},
-			Fields: map[string]*yang.Entry{
-				"field-d": {
-					Name: "field-d",
-					Parent: &yang.Entry{
-						Name: "c-container",
-						Parent: &yang.Entry{
-							Name: "b-container",
-							Parent: &yang.Entry{
-								Name: "a-module",
-							},
-						},
-					},
-				},
-			},
-		},
-		inField:         "field-d",
-		inAbsolutePaths: true,
-		wantPaths:       [][]string{{"", "b-container", "c-container", "field-d"}},
-	}, {
-		name: "top-level module - not valid to map",
-		inStruct: &Directory{
-			Name:   "CContainer",
-			Path:   []string{"", "c-container"}, // Does not have a valid module.
-			Fields: map[string]*yang.Entry{"top": {}},
-		},
-		inField: "top",
-		wantErr: true,
-	}, {
-		name: "list with leafref key",
-		inStruct: &Directory{
-			Name: "DList",
-			Path: []string{"", "d-module", "d-container", "d-list"},
-			ListAttr: &YangListAttr{
-				KeyElems: []*yang.Entry{
-					{
-						Name: "d-key",
-						Type: &yang.YangType{
-							Kind: yang.Yleafref,
-						},
-						Parent: &yang.Entry{
-							Name: "config",
-							Parent: &yang.Entry{
-								Name: "d-list",
-								Kind: yang.DirectoryEntry,
-								Dir: map[string]*yang.Entry{
-									"d-key": {
-										Name: "d-key",
-										Type: &yang.YangType{Kind: yang.Yleafref},
-									},
-								},
-								Parent: &yang.Entry{
-									Name: "d-container",
-									Parent: &yang.Entry{
-										Name: "d-module",
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			Fields: map[string]*yang.Entry{
-				"d-key": {
-					Name: "d-key",
-					Type: &yang.YangType{
-						Kind: yang.Yleafref,
-					},
-					Parent: &yang.Entry{
-						Name: "config",
-						Parent: &yang.Entry{
-							Name: "d-list",
-							Kind: yang.DirectoryEntry,
-							Dir: map[string]*yang.Entry{
-								"d-key": {
-									Name: "d-key",
-									Type: &yang.YangType{Kind: yang.Yleafref},
-								},
-							},
-							Parent: &yang.Entry{
-								Name: "d-container",
-								Parent: &yang.Entry{
-									Name: "d-module",
-								},
-							},
-						},
-					},
-				},
-			},
-			ShadowedFields: map[string]*yang.Entry{
-				"d-key": {
-					Name: "d-key",
-					Parent: &yang.Entry{
-						Name: "state",
-						Parent: &yang.Entry{
-							Name: "d-list",
-							Kind: yang.DirectoryEntry,
-							Dir: map[string]*yang.Entry{
-								"d-key": {
-									Name: "d-key",
-									Type: &yang.YangType{Kind: yang.Yleafref},
-								},
-							},
-							Parent: &yang.Entry{
-								Name: "d-container",
-								Parent: &yang.Entry{
-									Name: "d-module",
-								},
-							},
-						},
-					},
-				},
-			},
-		},
-		inField:         "d-key",
-		inCompressPaths: true,
-		wantPaths: [][]string{
-			{"config", "d-key"},
-			{"d-key"},
-		},
-	}, {
-		name: "list with leafref key with shadowSchemaPaths=true",
-		inStruct: &Directory{
-			Name: "DList",
-			Path: []string{"", "d-module", "d-container", "d-list"},
-			ListAttr: &YangListAttr{
-				KeyElems: []*yang.Entry{
-					{
-						Name: "d-key",
-						Type: &yang.YangType{
-							Kind: yang.Yleafref,
-						},
-						Parent: &yang.Entry{
-							Name: "config",
-							Parent: &yang.Entry{
-								Name: "d-list",
-								Kind: yang.DirectoryEntry,
-								Dir: map[string]*yang.Entry{
-									"d-key": {
-										Name: "d-key",
-										Type: &yang.YangType{Kind: yang.Yleafref},
-									},
-								},
-								Parent: &yang.Entry{
-									Name: "d-container",
-									Parent: &yang.Entry{
-										Name: "d-module",
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			Fields: map[string]*yang.Entry{
-				"d-key": {
-					Name: "d-key",
-					Type: &yang.YangType{
-						Kind: yang.Yleafref,
-					},
-					Parent: &yang.Entry{
-						Name: "config",
-						Parent: &yang.Entry{
-							Name: "d-list",
-							Kind: yang.DirectoryEntry,
-							Dir: map[string]*yang.Entry{
-								"d-key": {
-									Name: "d-key",
-									Type: &yang.YangType{Kind: yang.Yleafref},
-								},
-							},
-							Parent: &yang.Entry{
-								Name: "d-container",
-								Parent: &yang.Entry{
-									Name: "d-module",
-								},
-							},
-						},
-					},
-				},
-			},
-			ShadowedFields: map[string]*yang.Entry{
-				"d-key": {
-					Name: "d-key",
-					Parent: &yang.Entry{
-						Name: "state",
-						Parent: &yang.Entry{
-							Name: "d-list",
-							Kind: yang.DirectoryEntry,
-							Dir: map[string]*yang.Entry{
-								"d-key": {
-									Name: "d-key",
-									Type: &yang.YangType{Kind: yang.Yleafref},
-								},
-							},
-							Parent: &yang.Entry{
-								Name: "d-container",
-								Parent: &yang.Entry{
-									Name: "d-module",
-								},
-							},
-						},
-					},
-				},
-			},
-		},
-		inField:             "d-key",
-		inCompressPaths:     true,
-		inShadowSchemaPaths: true,
-		wantPaths: [][]string{
-			{"state", "d-key"},
-			{"d-key"},
-		},
-	}}
-
-	for _, tt := range tests {
-		got, err := findMapPaths(tt.inStruct, tt.inField, tt.inCompressPaths, tt.inShadowSchemaPaths, tt.inAbsolutePaths)
-		if err != nil {
-			if !tt.wantErr {
-				t.Errorf("%s: YANGCodeGenerator.findMapPaths(%v, %v): compress: %v, shadowSchemaPaths: %v, got unexpected error: %v",
-					tt.name, tt.inStruct, tt.inField, tt.inCompressPaths, tt.inShadowSchemaPaths, err)
-			}
-			continue
-		}
-
-		if diff := cmp.Diff(tt.wantPaths, got); diff != "" {
-			t.Errorf("%s: YANGCodeGenerator.findMapPaths(%v, %v): compress: %v, shadowSchemaPaths: %v, (-want, +got):\n%s", tt.name, tt.inStruct, tt.inField, tt.inCompressPaths, tt.inShadowSchemaPaths, diff)
-		}
-	}
-}
-
 func TestGenerateEnumMap(t *testing.T) {
 	tests := []struct {
 		name    string