@@ -1879,6 +1879,66 @@ func (e *ExampleAnnotation) UnmarshalJSON([]byte) error {
18791879 return fmt .Errorf ("unimplemented" )
18801880}
18811881
1882+ type ConfigStateContainer struct {
1883+ Int32Leaf * int32 `path:"state/int32-leaf" shadow-path:"config/int32-leaf"`
1884+ Int32LeafList []int32 `path:"state/int32-leaflist" shadow-path:"config/int32-leaflist"`
1885+ }
1886+
1887+ type ConfigStateRoot struct {
1888+ Child * ConfigStateContainer `path:"config-state"`
1889+ }
1890+
1891+ func configStateContainerParentSchema () * yang.Entry {
1892+ sch := & yang.Entry {
1893+ Name : "" ,
1894+ Kind : yang .DirectoryEntry ,
1895+ Dir : map [string ]* yang.Entry {
1896+ "config-state" : {
1897+ Name : "config-state" ,
1898+ Kind : yang .DirectoryEntry ,
1899+ Dir : map [string ]* yang.Entry {
1900+ "config" : {
1901+ Name : "config" ,
1902+ Kind : yang .DirectoryEntry ,
1903+ Dir : map [string ]* yang.Entry {
1904+ "int32-leaf" : {
1905+ Name : "int32-leaf" ,
1906+ Kind : yang .LeafEntry ,
1907+ Type : & yang.YangType {Kind : yang .Yint32 },
1908+ },
1909+ "int32-leaflist" : {
1910+ Name : "int32-leaflist" ,
1911+ Kind : yang .LeafEntry ,
1912+ ListAttr : yang .NewDefaultListAttr (),
1913+ Type : & yang.YangType {Kind : yang .Yint32 },
1914+ },
1915+ },
1916+ },
1917+ "state" : {
1918+ Name : "state" ,
1919+ Kind : yang .DirectoryEntry ,
1920+ Dir : map [string ]* yang.Entry {
1921+ "int32-leaf" : {
1922+ Name : "int32-leaf" ,
1923+ Kind : yang .LeafEntry ,
1924+ Type : & yang.YangType {Kind : yang .Yint32 },
1925+ },
1926+ "int32-leaflist" : {
1927+ Name : "int32-leaflist" ,
1928+ Kind : yang .LeafEntry ,
1929+ ListAttr : yang .NewDefaultListAttr (),
1930+ Type : & yang.YangType {Kind : yang .Yint32 },
1931+ },
1932+ },
1933+ },
1934+ },
1935+ },
1936+ },
1937+ }
1938+ addParents (sch )
1939+ return sch
1940+ }
1941+
18821942func TestSetNode (t * testing.T ) {
18831943 tests := []struct {
18841944 inDesc string
@@ -2012,6 +2072,97 @@ func TestSetNode(t *testing.T) {
20122072 },
20132073 },
20142074 },
2075+ {
2076+ inDesc : "success setting leaf-list field" ,
2077+ inSchema : configStateContainerParentSchema (),
2078+ inParentFn : func () interface {} { return & ConfigStateRoot {} },
2079+ inPath : mustPath ("/config-state/state/int32-leaflist" ),
2080+ inVal : & gpb.TypedValue {Value : & gpb.TypedValue_LeaflistVal {
2081+ LeaflistVal : & gpb.ScalarArray {
2082+ Element : []* gpb.TypedValue {{
2083+ Value : & gpb.TypedValue_IntVal {IntVal : 42 },
2084+ }, {
2085+ Value : & gpb.TypedValue_IntVal {IntVal : 43 },
2086+ }},
2087+ },
2088+ }},
2089+ inOpts : []SetNodeOpt {& InitMissingElements {}},
2090+ wantLeaf : []int32 {42 , 43 },
2091+ wantParent : & ConfigStateRoot {
2092+ Child : & ConfigStateContainer {
2093+ Int32LeafList : []int32 {42 , 43 },
2094+ },
2095+ },
2096+ },
2097+ {
2098+ inDesc : "success setting leaf-list field, with prefer shadow paths (path is shadow path)" ,
2099+ inSchema : configStateContainerParentSchema (),
2100+ inParentFn : func () interface {} { return & ConfigStateRoot {} },
2101+ inPath : mustPath ("/config-state/config/int32-leaflist" ),
2102+ inVal : & gpb.TypedValue {Value : & gpb.TypedValue_LeaflistVal {
2103+ LeaflistVal : & gpb.ScalarArray {
2104+ Element : []* gpb.TypedValue {{
2105+ Value : & gpb.TypedValue_IntVal {IntVal : 42 },
2106+ }, {
2107+ Value : & gpb.TypedValue_IntVal {IntVal : 43 },
2108+ }},
2109+ },
2110+ }},
2111+ inOpts : []SetNodeOpt {& InitMissingElements {}, & PreferShadowPath {}},
2112+ wantLeaf : []int32 {42 , 43 },
2113+ wantParent : & ConfigStateRoot {
2114+ Child : & ConfigStateContainer {
2115+ Int32LeafList : []int32 {42 , 43 },
2116+ },
2117+ },
2118+ },
2119+ {
2120+ inDesc : "success setting leaf-list field (path is not shadow path)" ,
2121+ inSchema : configStateContainerParentSchema (),
2122+ inParentFn : func () interface {} { return & ConfigStateRoot {} },
2123+ inPath : mustPath ("/config-state/state/int32-leaflist" ),
2124+ inVal : & gpb.TypedValue {Value : & gpb.TypedValue_LeaflistVal {
2125+ LeaflistVal : & gpb.ScalarArray {
2126+ Element : []* gpb.TypedValue {{
2127+ Value : & gpb.TypedValue_IntVal {IntVal : 42 },
2128+ }, {
2129+ Value : & gpb.TypedValue_IntVal {IntVal : 43 },
2130+ }},
2131+ },
2132+ }},
2133+ inOpts : []SetNodeOpt {& InitMissingElements {}},
2134+ wantLeaf : []int32 {42 , 43 },
2135+ wantParent : & ConfigStateRoot {
2136+ Child : & ConfigStateContainer {
2137+ Int32LeafList : []int32 {42 , 43 },
2138+ },
2139+ },
2140+ },
2141+ {
2142+ inDesc : "success setting leaf-list field, without prefer shadow paths (path is shadow path)" ,
2143+ inSchema : configStateContainerParentSchema (),
2144+ inParentFn : func () interface {} { return & ConfigStateRoot {} },
2145+ inPath : mustPath ("/config-state/config/int32-leaflist" ),
2146+ inVal : & gpb.TypedValue {Value : & gpb.TypedValue_LeaflistVal {
2147+ LeaflistVal : & gpb.ScalarArray {
2148+ Element : []* gpb.TypedValue {{
2149+ Value : & gpb.TypedValue_IntVal {IntVal : 42 },
2150+ }, {
2151+ Value : & gpb.TypedValue_IntVal {IntVal : 43 },
2152+ }},
2153+ },
2154+ }},
2155+ inOpts : []SetNodeOpt {& InitMissingElements {}},
2156+ // In this case, we've said "please do not prefer shadow paths" - i.e., just use whatever the path
2157+ // annotation tells you. We should have a no-op here -- since we were given a shadow path
2158+ // that we didn't want to unmarshal.
2159+ wantLeaf : nil ,
2160+ // But, hey, we said that we should initialise missing elements, so we do mutate the parent, just
2161+ // not with the leaf-list value.
2162+ wantParent : & ConfigStateRoot {
2163+ Child : & ConfigStateContainer {},
2164+ },
2165+ },
20152166 {
20162167 inDesc : "success setting int32 leaf list field" ,
20172168 inSchema : simpleSchema (),
@@ -2651,6 +2802,34 @@ func TestSetNode(t *testing.T) {
26512802 },
26522803 },
26532804 },
2805+ {
2806+ inDesc : "bug reproduction: avoid panic with invalid input type" ,
2807+ inSchema : containerWithStringKey (),
2808+ inParentFn : func () interface {} {
2809+ return & ContainerStruct1 {
2810+ StructKeyList : map [string ]* ListElemStruct1 {
2811+ "forty-two" : {
2812+ Key1 : ygot .String ("forty-two" ),
2813+ Outer : & OuterContainerType1 {},
2814+ },
2815+ },
2816+ }
2817+ },
2818+ inPath : mustPath ("/config/simple-key-list[key1=forty-two]/outer/inner/string-leaf-field" ),
2819+ inOpts : []SetNodeOpt {& InitMissingElements {}},
2820+ inVal : "hello" ,
2821+ wantParent : & ContainerStruct1 {
2822+ StructKeyList : map [string ]* ListElemStruct1 {
2823+ "forty-two" : {
2824+ Key1 : ygot .String ("forty-two" ),
2825+ Outer : & OuterContainerType1 {
2826+ Inner : & InnerContainerType1 {},
2827+ },
2828+ },
2829+ },
2830+ },
2831+ wantErrSubstring : "invalid input data" ,
2832+ },
26542833 }
26552834
26562835 for _ , tt := range tests {
0 commit comments