...

Source file src/cuelang.org/go/cue/path_test.go

Documentation: cuelang.org/go/cue

     1  // Copyright 2020 CUE Authors
     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 cue
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  )
    21  
    22  func TestPaths(t *testing.T) {
    23  	var r Runtime
    24  	inst, _ := r.Compile("", `
    25  		#Foo:   a: b: 1
    26  		"#Foo": c: d: 2
    27  		_foo: b: 5
    28  		a: 3
    29  		b: [4, 5, 6]
    30  		c: "#Foo": 7
    31  		map: [string]: int
    32  		list: [...int]
    33  
    34  		// Issue 2060
    35  		let X = {a: b: 0}
    36  		x: y: X.a
    37  	`)
    38  	testCases := []struct {
    39  		path Path
    40  		out  string
    41  		str  string
    42  		err  bool
    43  	}{{
    44  		path: MakePath(Str("list"), AnyIndex),
    45  		out:  "int",
    46  		str:  "list.[_]",
    47  	}, {
    48  
    49  		path: MakePath(Def("#Foo"), Str("a"), Str("b")),
    50  		out:  "1",
    51  		str:  "#Foo.a.b",
    52  	}, {
    53  		path: ParsePath(`#Foo.a.b`),
    54  		out:  "1",
    55  		str:  "#Foo.a.b",
    56  	}, {
    57  		path: ParsePath(`"#Foo".c.d`),
    58  		out:  "2",
    59  		str:  `"#Foo".c.d`,
    60  	}, {
    61  		// fallback Def(Foo) -> Def(#Foo)
    62  		path: MakePath(Def("Foo"), Str("a"), Str("b")),
    63  		out:  "1",
    64  		str:  "#Foo.a.b",
    65  	}, {
    66  		path: MakePath(Str("b"), Index(2)),
    67  		out:  "6",
    68  		str:  "b[2]", // #Foo.b.2
    69  	}, {
    70  		path: MakePath(Str("c"), Str("#Foo")),
    71  		out:  "7",
    72  		str:  `c."#Foo"`,
    73  	}, {
    74  		path: MakePath(Hid("_foo", "_"), Str("b")),
    75  		out:  "5",
    76  		str:  `_foo.b`,
    77  	}, {
    78  		path: ParsePath("#Foo.a.b"),
    79  		str:  "#Foo.a.b",
    80  		out:  "1",
    81  	}, {
    82  		path: ParsePath("#Foo.a.c"),
    83  		str:  "#Foo.a.c",
    84  		out:  `_|_ // field not found: c`,
    85  	}, {
    86  		path: ParsePath(`b[2]`),
    87  		str:  `b[2]`,
    88  		out:  "6",
    89  	}, {
    90  		path: ParsePath(`c."#Foo"`),
    91  		str:  `c."#Foo"`,
    92  		out:  "7",
    93  	}, {
    94  		path: ParsePath("foo._foo"),
    95  		str:  "_|_",
    96  		err:  true,
    97  		out:  `_|_ // invalid path: hidden label _foo not allowed`,
    98  	}, {
    99  		path: ParsePath(`c."#Foo`),
   100  		str:  "_|_",
   101  		err:  true,
   102  		out:  `_|_ // string literal not terminated`,
   103  	}, {
   104  		path: ParsePath(`b[a]`),
   105  		str:  "_|_",
   106  		err:  true,
   107  		out:  `_|_ // non-constant expression a`,
   108  	}, {
   109  		path: ParsePath(`b['1']`),
   110  		str:  "_|_",
   111  		err:  true,
   112  		out:  `_|_ // invalid string index '1'`,
   113  	}, {
   114  		path: ParsePath(`b[3T]`),
   115  		str:  "_|_",
   116  		err:  true,
   117  		out:  `_|_ // int label out of range (3000000000000 not >=0 and <= 268435454)`,
   118  	}, {
   119  		path: ParsePath(`b[3.3]`),
   120  		str:  "_|_",
   121  		err:  true,
   122  		out:  `_|_ // invalid literal 3.3`,
   123  	}, {
   124  		path: MakePath(Str("map"), AnyString),
   125  		out:  "int",
   126  		str:  "map.[_]",
   127  	}, {
   128  		path: MakePath(Str("list"), AnyIndex),
   129  		out:  "int",
   130  		str:  "list.[_]",
   131  	}, {
   132  		path: ParsePath("x.y"),
   133  		out:  "{\n\tb: 0\n}",
   134  		str:  "x.y",
   135  	}, {
   136  		path: ParsePath("x.y.b"),
   137  		out:  "0",
   138  		str:  "x.y.b",
   139  	}}
   140  
   141  	v := inst.Value()
   142  	for _, tc := range testCases {
   143  		t.Run(tc.str, func(t *testing.T) {
   144  			if gotErr := tc.path.Err() != nil; gotErr != tc.err {
   145  				t.Errorf("error: got %v; want %v", gotErr, tc.err)
   146  			}
   147  
   148  			w := v.LookupPath(tc.path)
   149  
   150  			if got := fmt.Sprint(w); got != tc.out {
   151  				t.Errorf("Value: got %v; want %v", got, tc.out)
   152  			}
   153  
   154  			if got := tc.path.String(); got != tc.str {
   155  				t.Errorf("String: got %v; want %v", got, tc.str)
   156  			}
   157  
   158  			if w.Err() != nil {
   159  				return
   160  			}
   161  
   162  			if got := w.Path().String(); got != tc.str {
   163  				t.Errorf("Path: got %v; want %v", got, tc.str)
   164  			}
   165  		})
   166  	}
   167  }
   168  
   169  var selectorTests = []struct {
   170  	sel          Selector
   171  	stype        SelectorType
   172  	string       string
   173  	unquoted     string
   174  	index        int
   175  	isHidden     bool
   176  	isConstraint bool
   177  	isDefinition bool
   178  	isString     bool
   179  	pkgPath      string
   180  }{{
   181  	sel:      Str("foo"),
   182  	stype:    StringLabel,
   183  	string:   "foo",
   184  	unquoted: "foo",
   185  	isString: true,
   186  }, {
   187  	sel:      Str("_foo"),
   188  	stype:    StringLabel,
   189  	string:   `"_foo"`,
   190  	unquoted: "_foo",
   191  	isString: true,
   192  }, {
   193  	sel:      Str(`a "b`),
   194  	stype:    StringLabel,
   195  	string:   `"a \"b"`,
   196  	unquoted: `a "b`,
   197  	isString: true,
   198  }, {
   199  	sel:    Index(5),
   200  	stype:  IndexLabel,
   201  	string: "5",
   202  	index:  5,
   203  }, {
   204  	sel:          Def("foo"),
   205  	stype:        DefinitionLabel,
   206  	string:       "#foo",
   207  	isDefinition: true,
   208  }, {
   209  	sel:          Str("foo").Optional(),
   210  	stype:        StringLabel | OptionalConstraint,
   211  	string:       "foo?",
   212  	unquoted:     "foo",
   213  	isString:     true,
   214  	isConstraint: true,
   215  }, {
   216  	sel:          Str("foo").Required(),
   217  	stype:        StringLabel | RequiredConstraint,
   218  	string:       "foo!",
   219  	unquoted:     "foo",
   220  	isString:     true,
   221  	isConstraint: true,
   222  }, {
   223  	sel:          Def("foo").Required().Optional(),
   224  	stype:        DefinitionLabel | OptionalConstraint,
   225  	string:       "#foo?",
   226  	isDefinition: true,
   227  	isConstraint: true,
   228  }, {
   229  	sel:          Def("foo").Optional().Required(),
   230  	stype:        DefinitionLabel | RequiredConstraint,
   231  	string:       "#foo!",
   232  	isDefinition: true,
   233  	isConstraint: true,
   234  }, {
   235  	sel:          AnyString,
   236  	stype:        StringLabel | PatternConstraint,
   237  	string:       "[_]",
   238  	isConstraint: true,
   239  }, {
   240  	sel:          AnyIndex,
   241  	stype:        IndexLabel | PatternConstraint,
   242  	string:       "[_]",
   243  	isConstraint: true,
   244  }, {
   245  	sel:      Hid("_foo", "example.com"),
   246  	stype:    HiddenLabel,
   247  	string:   "_foo",
   248  	isHidden: true,
   249  	pkgPath:  "example.com",
   250  }, {
   251  	sel:          Hid("_#foo", "example.com"),
   252  	stype:        HiddenDefinitionLabel,
   253  	string:       "_#foo",
   254  	isHidden:     true,
   255  	isDefinition: true,
   256  	pkgPath:      "example.com",
   257  }}
   258  
   259  func TestSelector(t *testing.T) {
   260  	for _, tc := range selectorTests {
   261  		t.Run(tc.sel.String(), func(t *testing.T) {
   262  			sel := tc.sel
   263  			if got, want := sel.Type(), tc.stype; got != want {
   264  				t.Errorf("unexpected type; got %v want %v", got, want)
   265  			}
   266  			if got, want := sel.String(), tc.string; got != want {
   267  				t.Errorf("unexpected sel.String result; got %q want %q", got, want)
   268  			}
   269  			if tc.unquoted == "" {
   270  				checkPanic(t, "Selector.Unquoted invoked on non-string label", func() {
   271  					sel.Unquoted()
   272  				})
   273  			} else {
   274  				if got, want := sel.Unquoted(), tc.unquoted; got != want {
   275  					t.Errorf("unexpected sel.Unquoted result; got %q want %q", got, want)
   276  				}
   277  			}
   278  			if sel.Type() != IndexLabel {
   279  				checkPanic(t, "Index called on non-index selector", func() {
   280  					sel.Index()
   281  				})
   282  			} else {
   283  				if got, want := sel.Index(), tc.index; got != want {
   284  					t.Errorf("unexpected sel.Index result; got %v want %v", got, want)
   285  				}
   286  			}
   287  			if got, want := sel.Type().IsHidden(), tc.isHidden; got != want {
   288  				t.Errorf("unexpected sel.IsHidden result; got %v want %v", got, want)
   289  			}
   290  			if got, want := sel.IsConstraint(), tc.isConstraint; got != want {
   291  				t.Errorf("unexpected sel.IsOptional result; got %v want %v", got, want)
   292  			}
   293  			if got, want := sel.IsString(), tc.isString; got != want {
   294  				t.Errorf("unexpected sel.IsString result; got %v want %v", got, want)
   295  			}
   296  			if got, want := sel.IsDefinition(), tc.isDefinition; got != want {
   297  				t.Errorf("unexpected sel.IsDefinition result; got %v want %v", got, want)
   298  			}
   299  			if got, want := sel.PkgPath(), tc.pkgPath; got != want {
   300  				t.Errorf("unexpected sel.PkgPath result; got %v want %v", got, want)
   301  			}
   302  		})
   303  	}
   304  }
   305  
   306  func TestSelectorTypeString(t *testing.T) {
   307  	if got, want := InvalidSelectorType.String(), "NoLabels"; got != want {
   308  		t.Errorf("unexpected SelectorType.String result; got %q want %q", got, want)
   309  	}
   310  	if got, want := PatternConstraint.String(), "PatternConstraint"; got != want {
   311  		t.Errorf("unexpected SelectorType.String result; got %q want %q", got, want)
   312  	}
   313  	if got, want := (StringLabel | OptionalConstraint).String(), "StringLabel|OptionalConstraint"; got != want {
   314  		t.Errorf("unexpected SelectorType.String result; got %q want %q", got, want)
   315  	}
   316  	if got, want := SelectorType(255).String(), "StringLabel|IndexLabel|DefinitionLabel|HiddenLabel|HiddenDefinitionLabel|OptionalConstraint|RequiredConstraint|PatternConstraint"; got != want {
   317  		t.Errorf("unexpected SelectorType.String result; got %q want %q", got, want)
   318  	}
   319  }
   320  
   321  func checkPanic(t *testing.T, wantPanicStr string, f func()) {
   322  	gotPanicStr := ""
   323  	func() {
   324  		defer func() {
   325  			e := recover()
   326  			if e == nil {
   327  				t.Errorf("function did not panic")
   328  				return
   329  			}
   330  			gotPanicStr = fmt.Sprint(e)
   331  		}()
   332  		f()
   333  	}()
   334  	if got, want := gotPanicStr, wantPanicStr; got != want {
   335  		t.Errorf("unexpected panic message; got %q want %q", got, want)
   336  	}
   337  }
   338  

View as plain text