cuelang.org/go@v0.13.0/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 *testing.T, m *cuetdtest.M) {
   100  			v := getValue(m, 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  func TestAttributeErr(t *testing.T) {
   111  	const config = `
   112  	a: {
   113  		a: 0 @foo(a,b,c=1)
   114  		b: 1 @bar(a,b,c,d=1) @foo(a,,d=1)
   115  	}
   116  	`
   117  	testCases := []struct {
   118  		path string
   119  		attr string
   120  		err  error
   121  	}{{
   122  		path: "a",
   123  		attr: "foo",
   124  		err:  nil,
   125  	}, {
   126  		path: "a",
   127  		attr: "bar",
   128  		err:  errors.New(`attribute "bar" does not exist`),
   129  	}, {
   130  		path: "xx",
   131  		attr: "bar",
   132  		err:  errors.New(`attribute "bar" does not exist`),
   133  	}, {
   134  		path: "e",
   135  		attr: "bar",
   136  		err:  errors.New(`attribute "bar" does not exist`),
   137  	}}
   138  	for _, tc := range testCases {
   139  		cuetdtest.FullMatrix.Run(t, tc.path+"-"+tc.attr, func(t *testing.T, m *cuetdtest.M) {
   140  			v := getValue(m, config).Lookup("a", tc.path)
   141  			a := v.Attribute(tc.attr)
   142  			err := a.Err()
   143  			if !cmpError(err, tc.err) {
   144  				t.Errorf("got %v; want %v", err, tc.err)
   145  			}
   146  		})
   147  	}
   148  }
   149  
   150  func TestAttributeName(t *testing.T) {
   151  	const config = `
   152  	a: 0 @foo(a,b,c=1) @bar()
   153  	`
   154  	cuetdtest.FullMatrix.Do(t, func(t *testing.T, m *cuetdtest.M) {
   155  		v := getValue(m, config).Lookup("a")
   156  		a := v.Attribute("foo")
   157  		if got, want := a.Name(), "foo"; got != want {
   158  			t.Errorf("got %v; want %v", got, want)
   159  		}
   160  	})
   161  }
   162  
   163  func TestAttributeString(t *testing.T) {
   164  	const config = `
   165  	a: {
   166  		a: 0 @foo(a,b,c=1)
   167  		b: 1 @bar(a,b,c,d=1) @foo(a,,d=1,e="x y","f g")
   168  	}
   169  	`
   170  	testCases := []struct {
   171  		path string
   172  		attr string
   173  		pos  int
   174  		str  string
   175  		err  error
   176  	}{{
   177  		path: "a",
   178  		attr: "foo",
   179  		pos:  0,
   180  		str:  "a",
   181  	}, {
   182  		path: "a",
   183  		attr: "foo",
   184  		pos:  2,
   185  		str:  "c=1",
   186  	}, {
   187  		path: "b",
   188  		attr: "bar",
   189  		pos:  3,
   190  		str:  "d=1",
   191  	}, {
   192  		path: "b",
   193  		attr: "foo",
   194  		pos:  3,
   195  		str:  `e="x y"`,
   196  	}, {
   197  		path: "b",
   198  		attr: "foo",
   199  		pos:  4,
   200  		str:  `f g`,
   201  	}, {
   202  		path: "e",
   203  		attr: "bar",
   204  		err:  errors.New(`attribute "bar" does not exist`),
   205  	}, {
   206  		path: "b",
   207  		attr: "foo",
   208  		pos:  5,
   209  		err:  errors.New("field does not exist"),
   210  	}}
   211  	for _, tc := range testCases {
   212  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *testing.T, m *cuetdtest.M) {
   213  			v := getValue(m, config).Lookup("a", tc.path)
   214  			a := v.Attribute(tc.attr)
   215  			got, err := a.String(tc.pos)
   216  			if !cmpError(err, tc.err) {
   217  				t.Errorf("err: got %v; want %v", err, tc.err)
   218  			}
   219  			if got != tc.str {
   220  				t.Errorf("str: got %v; want %v", got, tc.str)
   221  			}
   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 *testing.T, m *cuetdtest.M) {
   274  			v := getValue(m, 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  		c: 2 @nongo(10Mi)
   297  	}
   298  	`
   299  	testCases := []struct {
   300  		path string
   301  		attr string
   302  		pos  int
   303  		val  int64
   304  		err  error
   305  	}{{
   306  		path: "a",
   307  		attr: "foo",
   308  		pos:  0,
   309  		val:  1,
   310  	}, {
   311  		path: "b",
   312  		attr: "bar",
   313  		pos:  1,
   314  		val:  -4,
   315  	}, {
   316  		path: "e",
   317  		attr: "bar",
   318  		err:  errors.New(`attribute "bar" does not exist`),
   319  	}, {
   320  		path: "b",
   321  		attr: "foo",
   322  		pos:  4,
   323  		err:  errors.New("field does not exist"),
   324  	}, {
   325  		path: "a",
   326  		attr: "foo",
   327  		pos:  2,
   328  		err:  errors.New(`illegal number start "c=1"`),
   329  	}, {
   330  		path: "c",
   331  		attr: "nongo",
   332  		pos:  0,
   333  		val:  10 << 20,
   334  	}}
   335  	for _, tc := range testCases {
   336  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *testing.T, m *cuetdtest.M) {
   337  			v := getValue(m, config).Lookup("a", tc.path)
   338  			a := v.Attribute(tc.attr)
   339  			got, err := a.Int(tc.pos)
   340  			if !cmpError(err, tc.err) {
   341  				t.Errorf("err: got %v; want %v", err, tc.err)
   342  			}
   343  			if got != tc.val {
   344  				t.Errorf("val: got %v; want %v", got, tc.val)
   345  			}
   346  		})
   347  	}
   348  }
   349  
   350  func TestAttributeFlag(t *testing.T) {
   351  	const config = `
   352  	a: {
   353  		a: 0 @foo(a,b,c=1)
   354  		b: 1 @bar(a,b,c,d=1) @foo(a,,d=1)
   355  	}
   356  	`
   357  	testCases := []struct {
   358  		path string
   359  		attr string
   360  		pos  int
   361  		flag string
   362  		val  bool
   363  		err  error
   364  	}{{
   365  		path: "a",
   366  		attr: "foo",
   367  		pos:  0,
   368  		flag: "a",
   369  		val:  true,
   370  	}, {
   371  		path: "b",
   372  		attr: "bar",
   373  		pos:  1,
   374  		flag: "a",
   375  		val:  false,
   376  	}, {
   377  		path: "b",
   378  		attr: "bar",
   379  		pos:  0,
   380  		flag: "c",
   381  		val:  true,
   382  	}, {
   383  		path: "e",
   384  		attr: "bar",
   385  		err:  errors.New(`attribute "bar" does not exist`),
   386  	}, {
   387  		path: "b",
   388  		attr: "foo",
   389  		pos:  4,
   390  		err:  errors.New("field does not exist"),
   391  	}}
   392  	for _, tc := range testCases {
   393  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *testing.T, m *cuetdtest.M) {
   394  			v := getValue(m, config).Lookup("a", tc.path)
   395  			a := v.Attribute(tc.attr)
   396  			got, err := a.Flag(tc.pos, tc.flag)
   397  			if !cmpError(err, tc.err) {
   398  				t.Errorf("err: got %v; want %v", err, tc.err)
   399  			}
   400  			if got != tc.val {
   401  				t.Errorf("val: got %v; want %v", got, tc.val)
   402  			}
   403  		})
   404  	}
   405  }
   406  
   407  func TestAttributeLookup(t *testing.T) {
   408  	const config = `
   409  	a: {
   410  		a: 0 @foo(a,b,c=1)
   411  		b: 1 @bar(a,b,e =-5,d=1) @foo(a,,d=1)
   412  	}
   413  	`
   414  	testCases := []struct {
   415  		path string
   416  		attr string
   417  		pos  int
   418  		key  string
   419  		val  string
   420  		err  error
   421  	}{{
   422  		path: "a",
   423  		attr: "foo",
   424  		pos:  0,
   425  		key:  "c",
   426  		val:  "1",
   427  	}, {
   428  		path: "b",
   429  		attr: "bar",
   430  		pos:  1,
   431  		key:  "a",
   432  		val:  "",
   433  	}, {
   434  		path: "b",
   435  		attr: "bar",
   436  		pos:  0,
   437  		key:  "e",
   438  		val:  "-5",
   439  	}, {
   440  		path: "b",
   441  		attr: "bar",
   442  		pos:  0,
   443  		key:  "d",
   444  		val:  "1",
   445  	}, {
   446  		path: "b",
   447  		attr: "foo",
   448  		pos:  2,
   449  		key:  "d",
   450  		val:  "1",
   451  	}, {
   452  		path: "b",
   453  		attr: "foo",
   454  		pos:  2,
   455  		key:  "f",
   456  		val:  "",
   457  	}, {
   458  		path: "e",
   459  		attr: "bar",
   460  		err:  errors.New(`attribute "bar" does not exist`),
   461  	}, {
   462  		path: "b",
   463  		attr: "foo",
   464  		pos:  4,
   465  		err:  errors.New("field does not exist"),
   466  	}}
   467  	for _, tc := range testCases {
   468  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%s.%s:%d", tc.path, tc.attr, tc.pos), func(t *testing.T, m *cuetdtest.M) {
   469  			v := getValue(m, config).Lookup("a", tc.path)
   470  			a := v.Attribute(tc.attr)
   471  			got, _, err := a.Lookup(tc.pos, tc.key)
   472  			if !cmpError(err, tc.err) {
   473  				t.Errorf("err: got %v; want %v", err, tc.err)
   474  			}
   475  			if got != tc.val {
   476  				t.Errorf("val: got %v; want %v", got, tc.val)
   477  			}
   478  		})
   479  	}
   480  }