github.com/openconfig/goyang@v1.4.5/pkg/yang/ast_test.go (about) 1 // Copyright 2015 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package yang 16 17 import ( 18 "bytes" 19 "fmt" 20 "reflect" 21 "testing" 22 ) 23 24 type MainNode struct { 25 Name string `yang:"Name,nomerge"` 26 Source *Statement `yang:"Statement,nomerge"` 27 Parent Node `yang:"Parent,nomerge"` 28 Extensions []*Statement `yang:"Ext"` 29 30 Field *Value `yang:"field"` 31 Slice []*Value `yang:"slice"` 32 ChildNode *SubNode `yang:"child_node"` 33 ChildSlice []*SubNode `yang:"child_slice"` 34 ReqNode *ReqNode `yang:"req_node"` 35 MainField *Value `yang:"main_field,required=main_node"` 36 AltField *Value `yang:"alt_field,required=alt_node"` 37 } 38 39 func (m *MainNode) Kind() string { 40 if m.AltField != nil { 41 return "alt_node" 42 } 43 return "main_node" 44 } 45 46 func (m *MainNode) ParentNode() Node { return m.Parent } 47 func (m *MainNode) NName() string { return m.Name } 48 func (m *MainNode) Statement() *Statement { return m.Source } 49 func (m *MainNode) Exts() []*Statement { return m.Extensions } 50 51 func (m *MainNode) checkEqual(n Node) string { 52 o, ok := n.(*MainNode) 53 if !ok { 54 return fmt.Sprintf("expected *MainNode, got %T", n) 55 } 56 if m.Name != o.Name { 57 return fmt.Sprintf("got name %s, want %s", o.Name, m.Name) 58 } 59 if s := m.Source.checkEqual(o.Source); s != "" { 60 return s 61 } 62 if (m.Field == nil) != (o.Field == nil) { 63 if m.Field == nil { 64 return "unexpected field entry" 65 } 66 return "missing expected field entry" 67 } 68 if m.Field != nil { 69 if m.Field.Name != o.Field.Name { 70 return fmt.Sprintf("got field of %s, want %s", o.Field.Name, m.Field.Name) 71 } 72 } 73 if len(m.Slice) != len(o.Slice) { 74 return fmt.Sprintf("got slice of %d, want slice of %d", len(o.Slice), len(m.Slice)) 75 } 76 for x, s1 := range m.Slice { 77 s2 := o.Slice[x] 78 if s1.Name != s2.Name { 79 return fmt.Sprintf("slice[%d] got %s, want %s", x, s2.Name, s1.Name) 80 } 81 } 82 if (m.ChildNode == nil) != (o.ChildNode == nil) { 83 if m.ChildNode == nil { 84 return "unexpected child_node entry" 85 } 86 return "missing expected child_node entry" 87 } 88 if m.ChildNode != nil { 89 if s := m.ChildNode.checkEqual(o.ChildNode); s != "" { 90 return fmt.Sprintf("child_node: %s", s) 91 } 92 } 93 if len(m.ChildSlice) != len(o.ChildSlice) { 94 return fmt.Sprintf("got child_slice of %d, want slice of %d", len(o.ChildSlice), len(m.ChildSlice)) 95 } 96 for x, s1 := range m.ChildSlice { 97 s2 := o.ChildSlice[x] 98 if s := s1.checkEqual(s2); s != "" { 99 return fmt.Sprintf("child_slice[%d]: %s", x, s) 100 } 101 } 102 if (m.ReqNode == nil) != (o.ReqNode == nil) { 103 if m.ReqNode == nil { 104 return "unexpected req_node entry" 105 } 106 return "missing expected req_node entry" 107 } 108 if m.ReqNode != nil { 109 if s := m.ReqNode.checkEqual(o.ReqNode); s != "" { 110 return fmt.Sprintf("req_node: %s", s) 111 } 112 } 113 if (m.AltField == nil) != (o.AltField == nil) { 114 if m.AltField == nil { 115 return "unexpected alt_field entry" 116 } 117 return "missing expected alt_field entry" 118 } 119 if m.AltField != nil { 120 if m.AltField.Name != o.AltField.Name { 121 return fmt.Sprintf("got alt_field of %s, want %s", o.AltField.Name, m.AltField.Name) 122 } 123 } 124 return "" 125 } 126 127 type SubNode struct { 128 Name string `yang:"Name,nomerge"` 129 Source *Statement `yang:"Statement,nomerge"` 130 Parent Node `yang:"Parent,nomerge"` 131 Extensions []*Statement `yang:"Ext"` 132 133 SubField *Value `yang:"sub_field"` 134 } 135 136 func (SubNode) Kind() string { return "sub_node" } 137 func (s *SubNode) ParentNode() Node { return s.Parent } 138 func (s *SubNode) NName() string { return s.Name } 139 func (s *SubNode) Statement() *Statement { return s.Source } 140 func (s *SubNode) Exts() []*Statement { return s.Extensions } 141 142 func (s *SubNode) checkEqual(o *SubNode) string { 143 if s.Name != o.Name { 144 return fmt.Sprintf("got name %s, want %s", o.Name, s.Name) 145 } 146 if s := s.Source.checkEqual(o.Source); s != "" { 147 return s 148 } 149 if (s.SubField == nil) != (o.SubField == nil) { 150 if s.SubField == nil { 151 return "unexpected sub_field entry" 152 } 153 return "missing expected sub_field entry" 154 } 155 if s.SubField != nil { 156 if s.SubField.Name != o.SubField.Name { 157 return fmt.Sprintf("got sub_field of %s, want %s", o.SubField.Name, s.SubField.Name) 158 } 159 } 160 return "" 161 } 162 163 type ReqNode struct { 164 Name string `yang:"Name,nomerge"` 165 Source *Statement `yang:"Statement,nomerge"` 166 Parent Node `yang:"Parent,nomerge"` 167 168 ReqField *Value `yang:"req_field,required"` 169 AltReqField *Value `yang:"alt_req_field,required=alt_req_node"` 170 Field *Value `yang:"field"` 171 } 172 173 func (s *ReqNode) Kind() string { 174 return "req_node" 175 } 176 func (s *ReqNode) ParentNode() Node { return s.Parent } 177 func (s *ReqNode) NName() string { return s.Name } 178 func (s *ReqNode) Statement() *Statement { return s.Source } 179 func (m *ReqNode) Exts() []*Statement { return nil } 180 181 func (s *ReqNode) checkEqual(o *ReqNode) string { 182 if s.Name != o.Name { 183 return fmt.Sprintf("got name %s, want %s", o.Name, s.Name) 184 } 185 if s := s.Source.checkEqual(o.Source); s != "" { 186 return s 187 } 188 if (s.ReqField == nil) != (o.ReqField == nil) { 189 if s.ReqField == nil { 190 return "unexpected req_field entry" 191 } 192 return "missing expected req_field entry" 193 } 194 if s.ReqField != nil { 195 if s.ReqField.Name != o.ReqField.Name { 196 return fmt.Sprintf("got req_field of %s, want %s", o.ReqField.Name, s.ReqField.Name) 197 } 198 } 199 if (s.AltReqField == nil) != (o.AltReqField == nil) { 200 if s.AltReqField == nil { 201 return "unexpected alt_req_field entry" 202 } 203 return "missing expected alt_req_field entry" 204 } 205 if s.AltReqField != nil { 206 if s.AltReqField.Name != o.AltReqField.Name { 207 return fmt.Sprintf("got alt_req_field of %s, want %s", o.AltReqField.Name, s.AltReqField.Name) 208 } 209 } 210 return "" 211 } 212 213 func (s *Statement) checkEqual(o *Statement) string { 214 if (s == nil) != (o == nil) { 215 var b bytes.Buffer 216 if s == nil { 217 o.Write(&b, "") 218 return fmt.Sprintf("unexpected Statement entry\n%s", &b) 219 } 220 s.Write(&b, "") 221 return fmt.Sprintf("missing expected Statement entry\n%s", &b) 222 } 223 if s == nil { 224 return "" 225 } 226 var b1, b2 bytes.Buffer 227 s.Write(&b1, "") 228 o.Write(&b2, "") 229 ss := b1.String() 230 os := b2.String() 231 if ss != os { 232 return fmt.Sprintf("got statement:\n%swant:\n%s", os, ss) 233 } 234 return "" 235 } 236 237 func TestAST(t *testing.T) { 238 // Teach the AST parser about our testing nodes 239 type meta struct { 240 MainNode []*MainNode `yang:"main_node"` 241 } 242 243 old_aliases := aliases 244 aliases = map[string]string{ 245 "alt_node": "main_node", 246 } 247 248 for _, tt := range []struct { 249 line int 250 in string 251 out *MainNode 252 err string 253 }{ 254 { 255 line: line(), 256 in: ` 257 main_node the_node { 258 // This test is testing to make sure unknown statements, that 259 // might be extensions, are properly put in the Extensions slice. 260 // When an extension is used, it must be of the form "prefix:name". 261 // See https://tools.ietf.org/html/rfc6020#section-7.17 262 ex:ext1 value1; 263 ex:ext2 value2; 264 main_field foo; 265 } 266 `, 267 out: &MainNode{ 268 Source: SA("main_node", "the_node", 269 SA("ex:ext1", "value1"), 270 SA("ex:ext2", "value2"), 271 SA("main_field", "foo")), 272 Name: "the_node", 273 Extensions: []*Statement{ 274 SA("ex:ext1", "value1"), 275 SA("ex:ext2", "value2"), 276 }, 277 MainField: &Value{ 278 Name: "foo", 279 }, 280 }, 281 }, 282 { 283 line: line(), 284 in: ` 285 main_node the_node { 286 // This test tests fields, slices, and sub-statements. 287 field field_value; 288 slice sl1; 289 slice sl2; 290 child_node the_child { 291 sub_field val1; 292 } 293 child_slice element1 { 294 sub_field el1; 295 } 296 child_slice element2 { 297 sub_field el2; 298 } 299 main_field foo; 300 }`, 301 out: &MainNode{ 302 Source: SA("main_node", "the_node", 303 SA("field", "field_value"), 304 SA("slice", "sl1"), 305 SA("slice", "sl2"), 306 SA("child_node", "the_child", 307 SA("sub_field", "val1")), 308 SA("child_slice", "element1", 309 SA("sub_field", "el1")), 310 SA("child_slice", "element2", 311 SA("sub_field", "el2")), 312 SA("main_field", "foo"), 313 ), 314 Name: "the_node", 315 Field: &Value{ 316 Name: "field_value", 317 }, 318 Slice: []*Value{ 319 { 320 Name: "sl1", 321 }, 322 { 323 Name: "sl2", 324 }, 325 }, 326 ChildNode: &SubNode{ 327 Source: SA("child_node", "the_child", 328 SA("sub_field", "val1")), 329 Name: "the_child", 330 SubField: &Value{ 331 Name: "val1", 332 }, 333 }, 334 ChildSlice: []*SubNode{ 335 { 336 Source: SA("child_slice", "element1", 337 SA("sub_field", "el1")), 338 Name: "element1", 339 SubField: &Value{ 340 Name: "el1", 341 }, 342 }, 343 { 344 Source: SA("child_slice", "element2", 345 SA("sub_field", "el2")), 346 Name: "element2", 347 SubField: &Value{ 348 Name: "el2", 349 }, 350 }, 351 }, 352 MainField: &Value{ 353 Name: "foo", 354 }, 355 }, 356 }, 357 { 358 line: line(), 359 in: ` 360 // This test tests for the presence of a required field. 361 // main_node requires the field named "main_field". 362 main_node the_node { 363 main_field value1 { 364 } 365 } 366 `, 367 out: &MainNode{ 368 Source: SA("main_node", "the_node", 369 SA("main_field", "value1"), 370 ), 371 Name: "the_node", 372 MainField: &Value{ 373 Name: "value1", 374 }, 375 }, 376 }, 377 { 378 line: line(), 379 in: ` 380 // This test tests for the presence of a required= field. 381 // alt_node requires the field named "alt_field". 382 alt_node the_node { 383 alt_field value2 { 384 } 385 } 386 `, 387 out: &MainNode{ 388 Source: SA("alt_node", "the_node", 389 SA("alt_field", "value2"), 390 ), 391 Name: "the_node", 392 AltField: &Value{ 393 Name: "value2", 394 }, 395 }, 396 }, 397 { 398 line: line(), 399 in: ` 400 main_node the_node { 401 // This test tests that extensions are rejected when the node is not 402 // supposed to contain them. 403 req_node value1 { 404 req_field foo { 405 } 406 ex:ext1 value1; 407 ex:ext2 value2; 408 } 409 } 410 `, 411 err: `ast.yang:8:3: no extension function`, 412 }, 413 { 414 line: line(), 415 in: ` 416 main_node the_node { 417 // This test tests for the presence of a required field. 418 // req_node requires the field named "req_field". 419 req_node value1 { 420 req_field foo { 421 } 422 } 423 main_field foo; 424 } 425 `, 426 out: &MainNode{ 427 Source: SA("main_node", "the_node", 428 SA("req_node", "value1", 429 SA("req_field", "foo")), 430 SA("main_field", "foo"), 431 ), 432 Name: "the_node", 433 ReqNode: &ReqNode{ 434 Source: SA("req_node", "value1", 435 SA("req_field", "foo")), 436 Name: "value1", 437 ReqField: &Value{ 438 Name: "foo", 439 }, 440 }, 441 MainField: &Value{ 442 Name: "foo", 443 }, 444 }, 445 }, 446 { 447 line: line(), 448 in: ` 449 main_node the_node { 450 // This test tests that the absence of a required field fails. 451 // req_node requires the field named "req_field". 452 req_node value1 { 453 } 454 main_field foo; 455 } 456 `, 457 err: `ast.yang:5:2: missing required req_node field: req_field`, 458 }, 459 { 460 line: line(), 461 in: ` 462 main_node the_node { 463 // This test tests that the absence of a required field. 464 // main_node requires the field named "main_field". 465 req_node value1 { 466 req_field foo { 467 } 468 } 469 } 470 `, 471 err: `ast.yang:2:1: missing required main_node field: main_field`, 472 }, 473 { 474 line: line(), 475 in: ` 476 // This test tests that the alt_field, specified with 477 // required=alt_node, causes the AST construction to error when a 478 // main_node contains it. 479 main_node the_node { 480 main_field foo; 481 alt_field foo; 482 } 483 `, 484 err: `ast.yang:5:1: unknown main_node field: alt_field`, 485 }, 486 { 487 line: line(), 488 in: ` 489 // This test tests that required=alt_node enforces that 490 // alt_node must contain it. 491 alt_node the_node { 492 main_field foo; 493 alt_field foo; 494 } 495 `, 496 err: `ast.yang:4:1: unknown alt_node field: main_field`, 497 }, 498 { 499 line: line(), 500 in: ` 501 // This test tests that required=alt_node enforces that 502 // alt_node must contain it. 503 alt_node the_node { 504 } 505 `, 506 err: `ast.yang:4:1: missing required alt_node field: alt_field`, 507 }, 508 } { 509 ss, err := Parse(tt.in, "ast.yang") 510 if err != nil { 511 t.Errorf("%d: %v", tt.line, err) 512 continue 513 } 514 if len(ss) != 1 { 515 t.Errorf("%d: got %d results, want 1", tt.line, len(ss)) 516 continue 517 } 518 519 typeDict := newTypeDictionary() 520 initTypes(reflect.TypeOf(&meta{})) 521 522 ast, err := buildASTWithTypeDict(ss[0], typeDict) 523 switch { 524 case err == nil && tt.err == "": 525 if s := tt.out.checkEqual(ast); s != "" { 526 t.Errorf("%d: %s", tt.line, s) 527 } 528 case err == nil: 529 t.Errorf("%d: did not get expected error %s", tt.line, tt.err) 530 case tt.err == "": 531 t.Errorf("%d: %v", tt.line, err) 532 case err.Error() != tt.err: 533 t.Errorf("%d: got error %v, want %s", tt.line, err, tt.err) 534 } 535 } 536 537 aliases = old_aliases 538 }