@@ -1879,6 +1879,66 @@ func (e *ExampleAnnotation) UnmarshalJSON([]byte) error {
1879
1879
return fmt .Errorf ("unimplemented" )
1880
1880
}
1881
1881
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
+
1882
1942
func TestSetNode (t * testing.T ) {
1883
1943
tests := []struct {
1884
1944
inDesc string
@@ -2012,6 +2072,97 @@ func TestSetNode(t *testing.T) {
2012
2072
},
2013
2073
},
2014
2074
},
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
+ },
2015
2166
{
2016
2167
inDesc : "success setting int32 leaf list field" ,
2017
2168
inSchema : simpleSchema (),
@@ -2651,6 +2802,34 @@ func TestSetNode(t *testing.T) {
2651
2802
},
2652
2803
},
2653
2804
},
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
+ },
2654
2833
}
2655
2834
2656
2835
for _ , tt := range tests {
0 commit comments