cuelang.org/go@v0.10.1/cue/attribute_test.go (about)

     1  // Copyright 2021 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_test
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  
    21  	"cuelang.org/go/cue"
    22  	"cuelang.org/go/cue/errors"
    23  	"cuelang.org/go/internal/cuetdtest"
    24  )
    25  
    26  func TestAttributes(t *testing.T) {
    27  	const config = `
    28  	a: {
    29  		a: 0 @foo(a,b,c=1)
    30  		b: 1 @bar(a,b,c,d=1) @foo(a,,d=1)
    31  	}
    32  	b: {
    33  		@embed(foo)
    34  		3
    35  	} @field(foo)
    36  
    37  	c1: {} @step(1)
    38  	if true {
    39  		c2: { @step(2a) } @step(2b)
    40  		@step(2c)
    41  	}
    42  	c3: {} @step(3)
    43  	if false {
    44  		c4: { @step(4a) } @step(4b)
    45  		@step(4c)
    46  	}
    47  	`
    48  
    49  	testCases := []struct {
    50  		flags cue.AttrKind
    51  		path  string
    52  		out   string
    53  	}{{
    54  		flags: cue.FieldAttr,
    55  		path:  "a.a",
    56  		out:   "[@foo(a,b,c=1)]",
    57  	}, {
    58  		flags: cue.FieldAttr,
    59  		path:  "a.b",
    60  		out:   "[@bar(a,b,c,d=1) @foo(a,,d=1)]",
    61  	}, {
    62  		flags: cue.DeclAttr,
    63  		path:  "b",
    64  		out:   "[@embed(foo)]",
    65  	}, {
    66  		flags: cue.FieldAttr,
    67  		path:  "b",
    68  		out:   "[@field(foo)]",
    69  	}, {
    70  		flags: cue.ValueAttr,
    71  		path:  "b",
    72  		out:   "[@field(foo) @embed(foo)]",
    73  	}, {
    74  		flags: cue.ValueAttr,
    75  		path:  "c1",
    76  		out:   "[@step(1)]",
    77  	}, {
    78  		flags: cue.DeclAttr,
    79  		path:  "c2",
    80  		out:   "[@step(2a)]",
    81  	}, {
    82  		flags: cue.FieldAttr,
    83  		path:  "c2",
    84  		out:   "[@step(2b)]",
    85  	}, {
    86  		flags: cue.DeclAttr,
    87  		path:  "",
    88  		out:   "[@step(2c)]",
    89  	}, {
    90  		flags: cue.ValueAttr | cue.FieldAttr,
    91  		path:  "c3",
    92  		out:   "[@step(3)]",
    93  	}, {
    94  		flags: cue.ValueAttr | cue.FieldAttr,
    95  		path:  "c4",
    96  		out:   "[]",
    97  	}}
    98  	for _, tc := range testCases {
    99  		cuetdtest.FullMatrix.Run(t, tc.path, func(t *cuetdtest.M) {
   100  			v := getValue(t, config).LookupPath(cue.ParsePath(tc.path))
   101  			a := v.Attributes(tc.flags)
   102  			got := fmt.Sprint(a)
   103  			if got != tc.out {
   104  				t.Errorf("got %v; want %v", got, tc.out)
   105  			}
   106  
   107  		})
   108  	}
   109  }
   110  
   111  func TestAttributeErr(t *testing.T) {
   112  	const config = `
   113  	a: {
   114  		a: 0 @foo(a,b,c=1)
   115  		b: 1 @bar(a,b,c,d=1) @foo(a,,d=1)
   116  	}
   117  	`
   118  	testCases := []struct {
   119  		path string
   120  		attr string
   121  		err  error
   122  	}{{
   123  		path: "a",
   124  		attr: "foo",
   125  		err:  nil,
   126  	}, {
   127  		path: "a",
   128  		attr: "bar",
   129  		err:  errors.New(`attribute "bar" does not exist`),
   130  	}, {
   131  		path: "xx",
   132  		attr: "bar",
   133  		err:  errors.New(`attribute "bar" does not exist`),
   134  	}, {
   135  		path: "e",
   136  		attr: "bar",
   137  		err:  errors.New(`attribute "bar" does not exist`),
   138  	}}
   139  	for _, tc := range testCases {
   140  		cuetdtest.FullMatrix.Run(t, tc.path+"-"+tc.attr, func(t *cuetdtest.M) {
   141  			v := getValue(t, config).Lookup("a", tc.path)
   142  			a := v.Attribute(tc.attr)
   143  			err := a.Err()
   144  			if !cmpError(err, tc.err) {
   145  				t.Errorf("got %v; want %v", err, tc.err)
   146  			}
   147  		})
   148  	}
   149  }
   150  
   151  func TestAttributeName(t *testing.T) {
   152  	const config = `
   153  	a: 0 @foo(a,b,c=1) @bar()
   154  	`
   155  	cuetdtest.FullMatrix.Do(t, func(t *cuetdtest.M) {
   156  		v := getValue(t, config).Lookup("a")
   157  		a := v.Attribute("foo")
   158  		if got, want := a.Name(), "foo"; got != want {
   159  			t.Errorf("got %v; want %v", got, want)
   160  		}
   161  	})
   162  }
   163  
   164  func TestAttributeString(t *testing.T) {
   165  	const config = `
   166  	a: {
   167  		a: 0 @foo(a,b,c=1)
   168  		b: 1 @bar(a,b,c,d=1) @foo(a,,d=1,e="x y","f g")
   169  	}
   170  	`
   171  	testCases := []struct {
   172  		path string
   173  		attr string
   174  		pos  int
   175  		str  string
   176  		err  error
   177  	}{{
   178  		path: "a",
   179  		attr: "foo",
   180  		pos:  0,
   181  		str:  "a",
   182  	}, {
   183  		path: "a",
   184  		attr: "foo",
   185  		pos:  2,
   186  		str:  "c=1",
   187  	}, {
   188  		path: "b",
   189  		attr: "bar",
   190  		pos:  3,
   191  		str:  "d=1",
   192  	}, {
   193  		path: "b",
   194  		attr: "foo",
   195  		pos:  3,
   196  		str:  `e="x y"`,
   197  	}, {
   198  		path: "b",
   199  		attr: "foo",
   200  		pos:  4,
   201  		str:  `f g`,
   202  	}, {
   203  		path: "e",
   204  		attr: "bar",
   205  		err:  errors.New(`attribute "bar" does not exist`),
   206  	}, {
   207  		path: "b",
   208  		attr: "foo",
   209  		pos:  5,
   210  		err:  errors.New("field does not exist"),
   211  	}}
   212  	for _, tc := range testCases {
   213  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *cuetdtest.M) {
   214  			v := getValue(t, config).Lookup("a", tc.path)
   215  			a := v.Attribute(tc.attr)
   216  			got, err := a.String(tc.pos)
   217  			if !cmpError(err, tc.err) {
   218  				t.Errorf("err: got %v; want %v", err, tc.err)
   219  			}
   220  			if got != tc.str {
   221  				t.Errorf("str: got %v; want %v", got, tc.str)
   222  			}
   223  		})
   224  	}
   225  }
   226  
   227  func TestAttributeArg(t *testing.T) {
   228  	const config = `
   229  	a: 1 @foo(a,,d=1,e="x y","f g", with spaces ,  s=  spaces in value  )
   230  	`
   231  	testCases := []struct {
   232  		pos int
   233  		key string
   234  		val string
   235  		raw string
   236  	}{{
   237  		pos: 0,
   238  		key: "a",
   239  		val: "",
   240  		raw: "a",
   241  	}, {
   242  		pos: 1,
   243  		key: "",
   244  		val: "",
   245  		raw: "",
   246  	}, {
   247  		pos: 2,
   248  		key: "d",
   249  		val: "1",
   250  		raw: "d=1",
   251  	}, {
   252  		pos: 3,
   253  		key: "e",
   254  		val: "x y",
   255  		raw: `e="x y"`,
   256  	}, {
   257  		pos: 4,
   258  		key: "f g",
   259  		val: "",
   260  		raw: `"f g"`,
   261  	}, {
   262  		pos: 5,
   263  		key: "with spaces",
   264  		val: "",
   265  		raw: " with spaces ",
   266  	}, {
   267  		pos: 6,
   268  		key: "s",
   269  		val: "spaces in value",
   270  		raw: "  s=  spaces in value  ",
   271  	}}
   272  	for _, tc := range testCases {
   273  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%d", tc.pos), func(t *cuetdtest.M) {
   274  			v := getValue(t, config).Lookup("a")
   275  			a := v.Attribute("foo")
   276  			key, val := a.Arg(tc.pos)
   277  			raw := a.RawArg(tc.pos)
   278  			if got, want := key, tc.key; got != want {
   279  				t.Errorf("unexpected key; got %q want %q", got, want)
   280  			}
   281  			if got, want := val, tc.val; got != want {
   282  				t.Errorf("unexpected value; got %q want %q", got, want)
   283  			}
   284  			if got, want := raw, tc.raw; got != want {
   285  				t.Errorf("unexpected raw value; got %q want %q", got, want)
   286  			}
   287  		})
   288  	}
   289  }
   290  
   291  func TestAttributeInt(t *testing.T) {
   292  	const config = `
   293  	a: {
   294  		a: 0 @foo(1,3,c=1)
   295  		b: 1 @bar(a,-4,c,d=1) @foo(a,,d=1)
   296  	}
   297  	`
   298  	testCases := []struct {
   299  		path string
   300  		attr string
   301  		pos  int
   302  		val  int64
   303  		err  error
   304  	}{{
   305  		path: "a",
   306  		attr: "foo",
   307  		pos:  0,
   308  		val:  1,
   309  	}, {
   310  		path: "b",
   311  		attr: "bar",
   312  		pos:  1,
   313  		val:  -4,
   314  	}, {
   315  		path: "e",
   316  		attr: "bar",
   317  		err:  errors.New(`attribute "bar" does not exist`),
   318  	}, {
   319  		path: "b",
   320  		attr: "foo",
   321  		pos:  4,
   322  		err:  errors.New("field does not exist"),
   323  	}, {
   324  		path: "a",
   325  		attr: "foo",
   326  		pos:  2,
   327  		err:  errors.New(`strconv.ParseInt: parsing "c=1": invalid syntax`),
   328  	}}
   329  	for _, tc := range testCases {
   330  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *cuetdtest.M) {
   331  			v := getValue(t, config).Lookup("a", tc.path)
   332  			a := v.Attribute(tc.attr)
   333  			got, err := a.Int(tc.pos)
   334  			if !cmpError(err, tc.err) {
   335  				t.Errorf("err: got %v; want %v", err, tc.err)
   336  			}
   337  			if got != tc.val {
   338  				t.Errorf("val: got %v; want %v", got, tc.val)
   339  			}
   340  		})
   341  	}
   342  }
   343  
   344  func TestAttributeFlag(t *testing.T) {
   345  	const config = `
   346  	a: {
   347  		a: 0 @foo(a,b,c=1)
   348  		b: 1 @bar(a,b,c,d=1) @foo(a,,d=1)
   349  	}
   350  	`
   351  	testCases := []struct {
   352  		path string
   353  		attr string
   354  		pos  int
   355  		flag string
   356  		val  bool
   357  		err  error
   358  	}{{
   359  		path: "a",
   360  		attr: "foo",
   361  		pos:  0,
   362  		flag: "a",
   363  		val:  true,
   364  	}, {
   365  		path: "b",
   366  		attr: "bar",
   367  		pos:  1,
   368  		flag: "a",
   369  		val:  false,
   370  	}, {
   371  		path: "b",
   372  		attr: "bar",
   373  		pos:  0,
   374  		flag: "c",
   375  		val:  true,
   376  	}, {
   377  		path: "e",
   378  		attr: "bar",
   379  		err:  errors.New(`attribute "bar" does not exist`),
   380  	}, {
   381  		path: "b",
   382  		attr: "foo",
   383  		pos:  4,
   384  		err:  errors.New("field does not exist"),
   385  	}}
   386  	for _, tc := range testCases {
   387  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *cuetdtest.M) {
   388  			v := getValue(t, config).Lookup("a", tc.path)
   389  			a := v.Attribute(tc.attr)
   390  			got, err := a.Flag(tc.pos, tc.flag)
   391  			if !cmpError(err, tc.err) {
   392  				t.Errorf("err: got %v; want %v", err, tc.err)
   393  			}
   394  			if got != tc.val {
   395  				t.Errorf("val: got %v; want %v", got, tc.val)
   396  			}
   397  		})
   398  	}
   399  }
   400  
   401  func TestAttributeLookup(t *testing.T) {
   402  	const config = `
   403  	a: {
   404  		a: 0 @foo(a,b,c=1)
   405  		b: 1 @bar(a,b,e =-5,d=1) @foo(a,,d=1)
   406  	}
   407  	`
   408  	testCases := []struct {
   409  		path string
   410  		attr string
   411  		pos  int
   412  		key  string
   413  		val  string
   414  		err  error
   415  	}{{
   416  		path: "a",
   417  		attr: "foo",
   418  		pos:  0,
   419  		key:  "c",
   420  		val:  "1",
   421  	}, {
   422  		path: "b",
   423  		attr: "bar",
   424  		pos:  1,
   425  		key:  "a",
   426  		val:  "",
   427  	}, {
   428  		path: "b",
   429  		attr: "bar",
   430  		pos:  0,
   431  		key:  "e",
   432  		val:  "-5",
   433  	}, {
   434  		path: "b",
   435  		attr: "bar",
   436  		pos:  0,
   437  		key:  "d",
   438  		val:  "1",
   439  	}, {
   440  		path: "b",
   441  		attr: "foo",
   442  		pos:  2,
   443  		key:  "d",
   444  		val:  "1",
   445  	}, {
   446  		path: "b",
   447  		attr: "foo",
   448  		pos:  2,
   449  		key:  "f",
   450  		val:  "",
   451  	}, {
   452  		path: "e",
   453  		attr: "bar",
   454  		err:  errors.New(`attribute "bar" does not exist`),
   455  	}, {
   456  		path: "b",
   457  		attr: "foo",
   458  		pos:  4,
   459  		err:  errors.New("field does not exist"),
   460  	}}
   461  	for _, tc := range testCases {
   462  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *cuetdtest.M) {
   463  			v := getValue(t, config).Lookup("a", tc.path)
   464  			a := v.Attribute(tc.attr)
   465  			got, _, err := a.Lookup(tc.pos, tc.key)
   466  			if !cmpError(err, tc.err) {
   467  				t.Errorf("err: got %v; want %v", err, tc.err)
   468  			}
   469  			if got != tc.val {
   470  				t.Errorf("val: got %v; want %v", got, tc.val)
   471  			}
   472  		})
   473  	}
   474  }