1/* 2Copyright 2018 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package typed_test 18 19import ( 20 "fmt" 21 "testing" 22 23 "sigs.k8s.io/structured-merge-diff/v3/fieldpath" 24 "sigs.k8s.io/structured-merge-diff/v3/typed" 25 "sigs.k8s.io/structured-merge-diff/v3/value" 26) 27 28type objSetPair struct { 29 object typed.YAMLObject 30 set *fieldpath.Set 31} 32 33type fieldsetTestCase struct { 34 name string 35 rootTypeName string 36 schema typed.YAMLObject 37 pairs []objSetPair 38} 39 40var ( 41 // Short names for readable test cases. 42 _NS = fieldpath.NewSet 43 _P = fieldpath.MakePathOrDie 44 _KBF = fieldpath.KeyByFields 45 _V = value.NewValueInterface 46) 47 48var fieldsetCases = []fieldsetTestCase{{ 49 name: "simple pair", 50 rootTypeName: "stringPair", 51 schema: `types: 52- name: stringPair 53 map: 54 fields: 55 - name: key 56 type: 57 scalar: string 58 - name: value 59 type: 60 namedType: __untyped_atomic_ 61- name: __untyped_atomic_ 62 scalar: untyped 63 list: 64 elementType: 65 namedType: __untyped_atomic_ 66 elementRelationship: atomic 67 map: 68 elementType: 69 namedType: __untyped_atomic_ 70 elementRelationship: atomic 71`, 72 pairs: []objSetPair{ 73 {`{"key":"foo","value":1}`, _NS(_P("key"), _P("value"))}, 74 {`{"key":"foo","value":{"a": "b"}}`, _NS(_P("key"), _P("value"))}, 75 {`{"key":"foo","value":null}`, _NS(_P("key"), _P("value"))}, 76 {`{"key":"foo"}`, _NS(_P("key"))}, 77 {`{"key":"foo","value":true}`, _NS(_P("key"), _P("value"))}, 78 }, 79}, { 80 name: "struct grab bag", 81 rootTypeName: "myStruct", 82 schema: `types: 83- name: myStruct 84 map: 85 fields: 86 - name: numeric 87 type: 88 scalar: numeric 89 - name: string 90 type: 91 scalar: string 92 - name: bool 93 type: 94 scalar: boolean 95 - name: setStr 96 type: 97 list: 98 elementType: 99 scalar: string 100 elementRelationship: associative 101 - name: setBool 102 type: 103 list: 104 elementType: 105 scalar: boolean 106 elementRelationship: associative 107 - name: setNumeric 108 type: 109 list: 110 elementType: 111 scalar: numeric 112 elementRelationship: associative 113 - name: color 114 type: 115 map: 116 fields: 117 - name: R 118 type: 119 scalar: numeric 120 - name: G 121 type: 122 scalar: numeric 123 - name: B 124 type: 125 scalar: numeric 126 elementRelationship: atomic 127 - name: arbitraryWavelengthColor 128 type: 129 map: 130 elementType: 131 scalar: numeric 132 elementRelationship: atomic 133 - name: args 134 type: 135 list: 136 elementType: 137 map: 138 fields: 139 - name: key 140 type: 141 scalar: string 142 - name: value 143 type: 144 scalar: string 145 elementRelationship: atomic 146`, 147 pairs: []objSetPair{ 148 {`{"numeric":1}`, _NS(_P("numeric"))}, 149 {`{"numeric":3.14159}`, _NS(_P("numeric"))}, 150 {`{"string":"aoeu"}`, _NS(_P("string"))}, 151 {`{"bool":true}`, _NS(_P("bool"))}, 152 {`{"bool":false}`, _NS(_P("bool"))}, 153 {`{"setStr":["a","b","c"]}`, _NS( 154 _P("setStr", _V("a")), 155 _P("setStr", _V("b")), 156 _P("setStr", _V("c")), 157 )}, 158 {`{"setBool":[true,false]}`, _NS( 159 _P("setBool", _V(true)), 160 _P("setBool", _V(false)), 161 )}, 162 {`{"setNumeric":[1,2,3,3.14159]}`, _NS( 163 _P("setNumeric", _V(1)), 164 _P("setNumeric", _V(2)), 165 _P("setNumeric", _V(3)), 166 _P("setNumeric", _V(3.14159)), 167 )}, 168 {`{"color":{}}`, _NS(_P("color"))}, 169 {`{"color":null}`, _NS(_P("color"))}, 170 {`{"color":{"R":255,"G":0,"B":0}}`, _NS(_P("color"))}, 171 {`{"arbitraryWavelengthColor":{}}`, _NS(_P("arbitraryWavelengthColor"))}, 172 {`{"arbitraryWavelengthColor":null}`, _NS(_P("arbitraryWavelengthColor"))}, 173 {`{"arbitraryWavelengthColor":{"IR":255}}`, _NS(_P("arbitraryWavelengthColor"))}, 174 {`{"args":[]}`, _NS(_P("args"))}, 175 {`{"args":null}`, _NS(_P("args"))}, 176 {`{"args":[null]}`, _NS(_P("args"))}, 177 {`{"args":[{"key":"a","value":"b"},{"key":"c","value":"d"}]}`, _NS(_P("args"))}, 178 }, 179}, { 180 name: "associative list", 181 rootTypeName: "myRoot", 182 schema: `types: 183- name: myRoot 184 map: 185 fields: 186 - name: list 187 type: 188 namedType: myList 189 - name: atomicList 190 type: 191 namedType: mySequence 192- name: myList 193 list: 194 elementType: 195 namedType: myElement 196 elementRelationship: associative 197 keys: 198 - key 199 - id 200- name: mySequence 201 list: 202 elementType: 203 scalar: string 204 elementRelationship: atomic 205- name: myElement 206 map: 207 fields: 208 - name: key 209 type: 210 scalar: string 211 - name: id 212 type: 213 scalar: numeric 214 - name: value 215 type: 216 namedType: myValue 217 - name: bv 218 type: 219 scalar: boolean 220 - name: nv 221 type: 222 scalar: numeric 223- name: myValue 224 map: 225 elementType: 226 scalar: string 227`, 228 pairs: []objSetPair{ 229 {`{"list":[]}`, _NS()}, 230 {`{"list":[{"key":"a","id":1,"value":{"a":"a"}}]}`, _NS( 231 _P("list", _KBF("key", "a", "id", 1)), 232 _P("list", _KBF("key", "a", "id", 1), "key"), 233 _P("list", _KBF("key", "a", "id", 1), "id"), 234 _P("list", _KBF("key", "a", "id", 1), "value", "a"), 235 )}, 236 {`{"list":[{"key":"a","id":1},{"key":"a","id":2},{"key":"b","id":1}]}`, _NS( 237 _P("list", _KBF("key", "a", "id", 1)), 238 _P("list", _KBF("key", "a", "id", 2)), 239 _P("list", _KBF("key", "b", "id", 1)), 240 _P("list", _KBF("key", "a", "id", 1), "key"), 241 _P("list", _KBF("key", "a", "id", 1), "id"), 242 _P("list", _KBF("key", "a", "id", 2), "key"), 243 _P("list", _KBF("key", "a", "id", 2), "id"), 244 _P("list", _KBF("key", "b", "id", 1), "key"), 245 _P("list", _KBF("key", "b", "id", 1), "id"), 246 )}, 247 {`{"atomicList":["a","a","a"]}`, _NS(_P("atomicList"))}, 248 }, 249}} 250 251func (tt fieldsetTestCase) test(t *testing.T) { 252 parser, err := typed.NewParser(tt.schema) 253 if err != nil { 254 t.Fatalf("failed to create schema: %v", err) 255 } 256 for i, v := range tt.pairs { 257 v := v 258 t.Run(fmt.Sprintf("%v-%v", tt.name, i), func(t *testing.T) { 259 t.Parallel() 260 tv, err := parser.Type(tt.rootTypeName).FromYAML(v.object) 261 if err != nil { 262 t.Errorf("failed to parse object: %v", err) 263 } 264 fs, err := tv.ToFieldSet() 265 if err != nil { 266 t.Fatalf("got validation errors: %v", err) 267 } 268 if !fs.Equals(v.set) { 269 t.Errorf("wanted\n%s\ngot\n%s\n", v.set, fs) 270 } 271 }) 272 } 273} 274 275func TestToFieldSet(t *testing.T) { 276 for _, tt := range fieldsetCases { 277 tt := tt 278 t.Run(tt.name, func(t *testing.T) { 279 t.Parallel() 280 tt.test(t) 281 }) 282 } 283} 284