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  }