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

     1  // Copyright 2018 The 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  	"bytes"
    19  	"fmt"
    20  	"io"
    21  	"math"
    22  	"math/big"
    23  	"reflect"
    24  	"strconv"
    25  	"strings"
    26  	"testing"
    27  
    28  	"github.com/google/go-cmp/cmp"
    29  
    30  	"cuelang.org/go/cue"
    31  	"cuelang.org/go/cue/ast"
    32  	"cuelang.org/go/cue/cuecontext"
    33  	"cuelang.org/go/internal/astinternal"
    34  	"cuelang.org/go/internal/core/adt"
    35  	"cuelang.org/go/internal/core/debug"
    36  	"cuelang.org/go/internal/cuetdtest"
    37  	"cuelang.org/go/internal/cuetest"
    38  	"cuelang.org/go/internal/tdtest"
    39  )
    40  
    41  func getValue(t *cuetdtest.M, body string) cue.Value {
    42  	t.Helper()
    43  
    44  	ctx := t.Context()
    45  	return ctx.CompileString(body, cue.Filename("test"))
    46  }
    47  
    48  func mustCompile(t testing.TB, ctx *cue.Context, body string) cue.Value {
    49  	t.Helper()
    50  
    51  	val := ctx.CompileString(body, cue.Filename("test"))
    52  	if err := val.Err(); err != nil {
    53  		t.Fatal(err)
    54  	}
    55  	return val
    56  }
    57  
    58  func TestAPI(t *testing.T) {
    59  	testCases := []struct {
    60  		input string
    61  		fun   func(i cue.Value) cue.Value
    62  		want  string
    63  		skip  bool
    64  	}{{
    65  		// Issue #567
    66  		input: `
    67  		#runSpec: {action: foo: int}
    68  
    69  		v: {ction: foo: 1}
    70  				`,
    71  		fun: func(i cue.Value) cue.Value {
    72  			runSpec := i.LookupDef("#runSpec")
    73  			v := i.Lookup("v")
    74  			res := runSpec.Unify(v)
    75  			return res
    76  		},
    77  		want: "_|_ // #runSpec.ction: field not allowed",
    78  
    79  		skip: true,
    80  	}, {
    81  		// Issue #567
    82  		input: `
    83  		#runSpec: {action: foo: int}
    84  
    85  		v: {action: Foo: 1}
    86  				`,
    87  		fun: func(i cue.Value) cue.Value {
    88  			runSpec := i.LookupDef("#runSpec")
    89  			v := i.Lookup("v")
    90  			res := runSpec.Unify(v)
    91  			return res
    92  		},
    93  		want: "_|_ // #runSpec.action.Foo: field not allowed",
    94  	}, {
    95  		input: `
    96  		#runSpec: v: {action: foo: int}
    97  
    98  		w: {ction: foo: 1}
    99  					`,
   100  		fun: func(i cue.Value) cue.Value {
   101  			runSpec := i.LookupDef("#runSpec")
   102  			v := runSpec.Lookup("v")
   103  			w := i.Lookup("w")
   104  			res := w.Unify(v)
   105  			return res
   106  		},
   107  		want: "_|_ // w.ction: field not allowed",
   108  	}, {
   109  		// Issue #1879
   110  		input: `
   111  		#Steps: {
   112  			...
   113  		}
   114  
   115  		test: #Steps & {
   116  			if true {
   117  				test1: "test1"
   118  			}
   119  			if false {
   120  				test2: "test2"
   121  			}
   122  		}
   123  		`,
   124  
   125  		fun: func(v cue.Value) (val cue.Value) {
   126  			sub := v.LookupPath(cue.ParsePath("test"))
   127  			st, err := sub.Struct()
   128  			if err != nil {
   129  				panic(err)
   130  			}
   131  
   132  			for i := 0; i < st.Len(); i++ {
   133  				val = st.Field(i).Value
   134  			}
   135  
   136  			return val
   137  		},
   138  		want: `"test1"`,
   139  	}}
   140  	for _, tc := range testCases {
   141  		if tc.skip {
   142  			continue
   143  		}
   144  		cuetdtest.FullMatrix.Run(t, "", func(t *cuetdtest.M) {
   145  			t.TODO_V3()
   146  
   147  			ctx := t.Context()
   148  
   149  			valIn := mustCompile(t, ctx, tc.input)
   150  			valOut := tc.fun(valIn)
   151  			got := fmt.Sprintf("%+v", valOut)
   152  			if got != tc.want {
   153  				t.Errorf("got:\n%s\nwant:\n%s", got, tc.want)
   154  			}
   155  		})
   156  	}
   157  }
   158  
   159  func TestValueType(t *testing.T) {
   160  	testCases := []struct {
   161  		value          string
   162  		kind           cue.Kind
   163  		incompleteKind cue.Kind
   164  		json           string
   165  		valid          bool
   166  		concrete       bool
   167  		closed         bool
   168  		// pos            token.Pos
   169  	}{{ // Not a concrete value.
   170  		value:          `v: _`,
   171  		kind:           cue.BottomKind,
   172  		incompleteKind: cue.TopKind,
   173  	}, {
   174  		value:          `v: _|_`,
   175  		kind:           cue.BottomKind,
   176  		incompleteKind: cue.BottomKind,
   177  		concrete:       true,
   178  	}, {
   179  		value:          `v: 1&2`,
   180  		kind:           cue.BottomKind,
   181  		incompleteKind: cue.BottomKind,
   182  		concrete:       true,
   183  	}, {
   184  		value:          `v: b, b: 1&2`,
   185  		kind:           cue.BottomKind,
   186  		incompleteKind: cue.BottomKind,
   187  		concrete:       true,
   188  	}, {
   189  		value:          `v: (b[a]), b: 1, a: 1`,
   190  		kind:           cue.BottomKind,
   191  		incompleteKind: cue.BottomKind,
   192  		concrete:       true,
   193  	}, { // TODO: should be error{
   194  		value: `v: (b)
   195  			b: bool`,
   196  		kind:           cue.BottomKind,
   197  		incompleteKind: cue.BoolKind,
   198  	}, {
   199  		value:          `v: ([][b]), b: "d"`,
   200  		kind:           cue.BottomKind,
   201  		incompleteKind: cue.BottomKind,
   202  		concrete:       true,
   203  	}, {
   204  		value:          `v: null`,
   205  		kind:           cue.NullKind,
   206  		incompleteKind: cue.NullKind,
   207  		concrete:       true,
   208  	}, {
   209  		value:          `v: true`,
   210  		kind:           cue.BoolKind,
   211  		incompleteKind: cue.BoolKind,
   212  		concrete:       true,
   213  	}, {
   214  		value:          `v: false`,
   215  		kind:           cue.BoolKind,
   216  		incompleteKind: cue.BoolKind,
   217  		concrete:       true,
   218  	}, {
   219  		value:          `v: bool`,
   220  		kind:           cue.BottomKind,
   221  		incompleteKind: cue.BoolKind,
   222  	}, {
   223  		value:          `v: 2`,
   224  		kind:           cue.IntKind,
   225  		incompleteKind: cue.IntKind,
   226  		concrete:       true,
   227  	}, {
   228  		value:          `v: 2.0`,
   229  		kind:           cue.FloatKind,
   230  		incompleteKind: cue.FloatKind,
   231  		concrete:       true,
   232  	}, {
   233  		value:          `v: 2.0Mi`,
   234  		kind:           cue.IntKind,
   235  		incompleteKind: cue.IntKind,
   236  		concrete:       true,
   237  	}, {
   238  		value:          `v: 14_000`,
   239  		kind:           cue.IntKind,
   240  		incompleteKind: cue.IntKind,
   241  		concrete:       true,
   242  	}, {
   243  		value:          `v: >=0 & <5`,
   244  		kind:           cue.BottomKind,
   245  		incompleteKind: cue.NumberKind,
   246  	}, {
   247  		value:          `v: float`,
   248  		kind:           cue.BottomKind,
   249  		incompleteKind: cue.FloatKind,
   250  	}, {
   251  		value:          `v: "str"`,
   252  		kind:           cue.StringKind,
   253  		incompleteKind: cue.StringKind,
   254  		concrete:       true,
   255  	}, {
   256  		value:          "v: '''\n'''",
   257  		kind:           cue.BytesKind,
   258  		incompleteKind: cue.BytesKind,
   259  		concrete:       true,
   260  	}, {
   261  		value:          "v: string",
   262  		kind:           cue.BottomKind,
   263  		incompleteKind: cue.StringKind,
   264  	}, {
   265  		value:          `v: {}`,
   266  		kind:           cue.StructKind,
   267  		incompleteKind: cue.StructKind,
   268  		concrete:       true,
   269  	}, {
   270  		value:          `v: close({})`,
   271  		kind:           cue.StructKind,
   272  		incompleteKind: cue.StructKind,
   273  		concrete:       true,
   274  		closed:         true,
   275  	}, {
   276  		value:          `v: []`,
   277  		kind:           cue.ListKind,
   278  		incompleteKind: cue.ListKind,
   279  		concrete:       true,
   280  		closed:         true,
   281  	}, {
   282  		value:          `v: [...int]`,
   283  		kind:           cue.BottomKind,
   284  		incompleteKind: cue.ListKind,
   285  		concrete:       false,
   286  	}, {
   287  		value:    `v: {a: int, b: [1][a]}.b`,
   288  		kind:     cue.BottomKind,
   289  		concrete: false,
   290  	}, {
   291  		value: `import "time"
   292  		v: time.Time`,
   293  		kind:           cue.BottomKind,
   294  		incompleteKind: cue.StringKind,
   295  		concrete:       false,
   296  	}, {
   297  		value: `import "time"
   298  		v: {a: time.Time}.a`,
   299  		kind:           cue.BottomKind,
   300  		incompleteKind: cue.StringKind,
   301  		concrete:       false,
   302  	}, {
   303  		value: `import "time"
   304  			v: {a: time.Time & string}.a`,
   305  		kind:           cue.BottomKind,
   306  		incompleteKind: cue.StringKind,
   307  		concrete:       false,
   308  	}, {
   309  		value: `import "strings"
   310  			v: {a: strings.ContainsAny("D")}.a`,
   311  		kind:           cue.BottomKind,
   312  		incompleteKind: cue.StringKind,
   313  		concrete:       false,
   314  	}, {
   315  		value: `import "struct"
   316  		v: {a: struct.MaxFields(2) & {}}.a`,
   317  		kind:           cue.StructKind, // Can determine a valid struct already.
   318  		incompleteKind: cue.StructKind,
   319  		concrete:       true,
   320  	}, {
   321  		value: `v: #Foo
   322  		#Foo: {
   323  			name: string,
   324  			...
   325  		}`,
   326  		kind:           cue.StructKind,
   327  		incompleteKind: cue.StructKind,
   328  		concrete:       true,
   329  	}, {
   330  		value: `v: #Foo
   331  			#Foo: {
   332  				name: string,
   333  			}`,
   334  		kind:           cue.StructKind,
   335  		incompleteKind: cue.StructKind,
   336  		concrete:       true,
   337  		closed:         true,
   338  	}, {
   339  		value: `v: #Foo | int
   340  		#Foo: {
   341  			name: string,
   342  			}`,
   343  		incompleteKind: cue.StructKind | cue.IntKind,
   344  		// Hard to tell what is correct here, but For backwards compatibility,
   345  		// this is false.
   346  		closed: false,
   347  	}}
   348  	for _, tc := range testCases {
   349  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   350  			val := getValue(t, tc.value)
   351  			v := val.Lookup("v")
   352  			if got := v.Kind(); got != tc.kind {
   353  				t.Errorf("Kind: got %x; want %x", int(got), int(tc.kind))
   354  			}
   355  			want := tc.incompleteKind | cue.BottomKind
   356  			if got := v.IncompleteKind(); got != want {
   357  				t.Errorf("IncompleteKind: got %x; want %x", int(got), int(want))
   358  			}
   359  			if got := v.IsConcrete(); got != tc.concrete {
   360  				t.Errorf("IsConcrete: got %v; want %v", got, tc.concrete)
   361  			}
   362  			if got := v.IsClosed(); got != tc.closed {
   363  				t.Errorf("IsClosed: got %v; want %v", got, tc.closed)
   364  			}
   365  		})
   366  	}
   367  }
   368  
   369  func TestInt(t *testing.T) {
   370  	testCases := []struct {
   371  		value  string
   372  		int    int64
   373  		uint   uint64
   374  		base   int
   375  		err    string
   376  		errU   string
   377  		notInt bool
   378  	}{{
   379  		value: "1",
   380  		int:   1,
   381  		uint:  1,
   382  	}, {
   383  		value: "-1",
   384  		int:   -1,
   385  		uint:  0,
   386  		errU:  cue.ErrAbove.Error(),
   387  	}, {
   388  		value: "-111222333444555666777888999000",
   389  		int:   math.MinInt64,
   390  		uint:  0,
   391  		err:   cue.ErrAbove.Error(),
   392  		errU:  cue.ErrAbove.Error(),
   393  	}, {
   394  		value: "111222333444555666777888999000",
   395  		int:   math.MaxInt64,
   396  		uint:  math.MaxUint64,
   397  		err:   cue.ErrBelow.Error(),
   398  		errU:  cue.ErrBelow.Error(),
   399  	}, {
   400  		value:  "1.0",
   401  		err:    "cannot use value 1.0 (type float) as int",
   402  		errU:   "cannot use value 1.0 (type float) as int",
   403  		notInt: true,
   404  	}, {
   405  		value:  "int",
   406  		err:    "non-concrete value int",
   407  		errU:   "non-concrete value int",
   408  		notInt: true,
   409  	}, {
   410  		value:  "_|_",
   411  		err:    "explicit error (_|_ literal) in source",
   412  		errU:   "explicit error (_|_ literal) in source",
   413  		notInt: true,
   414  	}}
   415  	for _, tc := range testCases {
   416  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   417  			n := getValue(t, tc.value)
   418  			base := 10
   419  			if tc.base > 0 {
   420  				base = tc.base
   421  			}
   422  			b, err := n.AppendInt(nil, base)
   423  			if checkFailed(t.T, err, tc.err, "append") {
   424  				want := tc.value
   425  				if got := string(b); got != want {
   426  					t.Errorf("append: got %v; want %v", got, want)
   427  				}
   428  			}
   429  
   430  			vi, err := n.Int64()
   431  			checkErr(t.T, err, tc.err, "Int64")
   432  			if vi != tc.int {
   433  				t.Errorf("Int64: got %v; want %v", vi, tc.int)
   434  			}
   435  
   436  			vu, err := n.Uint64()
   437  			checkErr(t.T, err, tc.errU, "Uint64")
   438  			if vu != uint64(tc.uint) {
   439  				t.Errorf("Uint64: got %v; want %v", vu, tc.uint)
   440  			}
   441  		})
   442  	}
   443  }
   444  
   445  func TestFloat(t *testing.T) {
   446  	testCases := []struct {
   447  		value   string
   448  		float   string
   449  		float64 float64
   450  		mant    string
   451  		exp     int
   452  		fmt     byte
   453  		prec    int
   454  		kind    cue.Kind
   455  		err     string
   456  	}{{
   457  		value:   "1",
   458  		float:   "1",
   459  		mant:    "1",
   460  		exp:     0,
   461  		float64: 1,
   462  		fmt:     'g',
   463  		kind:    cue.IntKind,
   464  	}, {
   465  		value:   "-1",
   466  		float:   "-1",
   467  		mant:    "-1",
   468  		exp:     0,
   469  		float64: -1,
   470  		fmt:     'g',
   471  		kind:    cue.IntKind,
   472  	}, {
   473  		value:   "0.0",
   474  		float:   "0.0",
   475  		mant:    "0",
   476  		exp:     -1,
   477  		float64: 0.0,
   478  		fmt:     'g',
   479  		kind:    cue.FloatKind,
   480  	}, {
   481  		value:   "1.0",
   482  		float:   "1.0",
   483  		mant:    "10",
   484  		exp:     -1,
   485  		float64: 1.0,
   486  		fmt:     'g',
   487  		kind:    cue.FloatKind,
   488  	}, {
   489  		value:   "2.6",
   490  		float:   "2.6",
   491  		mant:    "26",
   492  		exp:     -1,
   493  		float64: 2.6,
   494  		fmt:     'g',
   495  		kind:    cue.FloatKind,
   496  	}, {
   497  		value:   "20.600",
   498  		float:   "20.60",
   499  		mant:    "20600",
   500  		exp:     -3,
   501  		float64: 20.60,
   502  		prec:    2,
   503  		fmt:     'f',
   504  		kind:    cue.FloatKind,
   505  	}, {
   506  		value:   "1/0",
   507  		float:   "",
   508  		float64: 0,
   509  		prec:    2,
   510  		fmt:     'f',
   511  		err:     "division by zero",
   512  		kind:    cue.BottomKind,
   513  	}, {
   514  		value:   "1.797693134862315708145274237317043567982e+308",
   515  		float:   "1.8e+308",
   516  		mant:    "1797693134862315708145274237317043567982",
   517  		exp:     269,
   518  		float64: math.Inf(1),
   519  		prec:    2,
   520  		fmt:     'g',
   521  		err:     cue.ErrAbove.Error(),
   522  		kind:    cue.FloatKind,
   523  	}, {
   524  		value:   "-1.797693134862315708145274237317043567982e+308",
   525  		float:   "-1.8e+308",
   526  		mant:    "-1797693134862315708145274237317043567982",
   527  		exp:     269,
   528  		float64: math.Inf(-1),
   529  		prec:    2,
   530  		fmt:     'g',
   531  		kind:    cue.FloatKind,
   532  		err:     cue.ErrBelow.Error(),
   533  	}, {
   534  		value:   "4.940656458412465441765687928682213723650e-324",
   535  		float:   "4.941e-324",
   536  		mant:    "4940656458412465441765687928682213723650",
   537  		exp:     -363,
   538  		float64: 0,
   539  		prec:    4,
   540  		fmt:     'g',
   541  		kind:    cue.FloatKind,
   542  		err:     cue.ErrBelow.Error(),
   543  	}, {
   544  		value:   "-4.940656458412465441765687928682213723650e-324",
   545  		float:   "-4.940656458412465441765687928682213723650e-324",
   546  		mant:    "-4940656458412465441765687928682213723650",
   547  		exp:     -363,
   548  		float64: 0,
   549  		prec:    -1,
   550  		fmt:     'g',
   551  		kind:    cue.FloatKind,
   552  		err:     cue.ErrAbove.Error(),
   553  	}}
   554  	for _, tc := range testCases {
   555  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   556  			n := getValue(t, tc.value)
   557  			if n.Kind() != tc.kind {
   558  				t.Fatal("Not a number")
   559  			}
   560  
   561  			var mant big.Int
   562  			exp, err := n.MantExp(&mant)
   563  			mstr := ""
   564  			if err == nil {
   565  				mstr = mant.String()
   566  			}
   567  			if exp != tc.exp || mstr != tc.mant {
   568  				t.Errorf("mantExp: got %s %d; want %s %d", mstr, exp, tc.mant, tc.exp)
   569  			}
   570  
   571  			b, _ := n.AppendFloat(nil, tc.fmt, tc.prec)
   572  			want := tc.float
   573  			if got := string(b); got != want {
   574  				t.Errorf("append: got %v; want %v", got, want)
   575  			}
   576  
   577  			f, err := n.Float64()
   578  			checkErr(t.T, err, tc.err, "Float64")
   579  			if f != tc.float64 {
   580  				t.Errorf("Float64: got %v; want %v", f, tc.float64)
   581  			}
   582  		})
   583  	}
   584  }
   585  
   586  func TestString(t *testing.T) {
   587  	testCases := []struct {
   588  		value string
   589  		str   string
   590  		err   string
   591  	}{{
   592  		value: `""`,
   593  		str:   ``,
   594  	}, {
   595  		value: `"Hello world!"`,
   596  		str:   `Hello world!`,
   597  	}, {
   598  		value: `"Hello \(#world)!"
   599  		#world: "world"`,
   600  		str: `Hello world!`,
   601  	}, {
   602  		value: `string`,
   603  		err:   "non-concrete value string",
   604  	}}
   605  	for _, tc := range testCases {
   606  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   607  			str, err := getValue(t, tc.value).String()
   608  			checkFatal(t.T, err, tc.err, "init")
   609  			if str != tc.str {
   610  				t.Errorf("String: got %q; want %q", str, tc.str)
   611  			}
   612  
   613  			b, err := getValue(t, tc.value).Bytes()
   614  			checkFatal(t.T, err, tc.err, "init")
   615  			if got := string(b); got != tc.str {
   616  				t.Errorf("Bytes: got %q; want %q", got, tc.str)
   617  			}
   618  
   619  			r, err := getValue(t, tc.value).Reader()
   620  			checkFatal(t.T, err, tc.err, "init")
   621  			b, _ = io.ReadAll(r)
   622  			if got := string(b); got != tc.str {
   623  				t.Errorf("Reader: got %q; want %q", got, tc.str)
   624  			}
   625  		})
   626  	}
   627  }
   628  
   629  func TestError(t *testing.T) {
   630  	testCases := []struct {
   631  		value string
   632  		err   string
   633  	}{{
   634  		value: `_|_`,
   635  		err:   "explicit error (_|_ literal) in source",
   636  	}, {
   637  		value: `"Hello world!"`,
   638  	}, {
   639  		value: `string`,
   640  		err:   "",
   641  	}}
   642  	for _, tc := range testCases {
   643  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   644  			err := getValue(t, tc.value).Err()
   645  			checkErr(t.T, err, tc.err, "init")
   646  		})
   647  	}
   648  }
   649  
   650  func TestNull(t *testing.T) {
   651  	testCases := []struct {
   652  		value string
   653  		err   string
   654  	}{{
   655  		value: `v: _|_`,
   656  		err:   "explicit error (_|_ literal) in source",
   657  	}, {
   658  		value: `v: "str"`,
   659  		err:   "cannot use value \"str\" (type string) as null",
   660  	}, {
   661  		value: `v: null`,
   662  	}, {
   663  		value: `v: _`,
   664  		err:   "non-concrete value _",
   665  	}}
   666  	for _, tc := range testCases {
   667  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   668  			v := getValue(t, tc.value).Lookup("v")
   669  			err := v.Null()
   670  			checkErr(t.T, err, tc.err, "init")
   671  			wantBool := err == nil
   672  			gotBool := v.IsNull()
   673  			if wantBool != gotBool {
   674  				t.Fatalf("IsNull reported %v, but Null reported: %v", gotBool, err)
   675  			}
   676  		})
   677  	}
   678  }
   679  
   680  func TestBool(t *testing.T) {
   681  	testCases := []struct {
   682  		value string
   683  		bool  bool
   684  		err   string
   685  	}{{
   686  		value: `_|_`,
   687  		err:   "explicit error (_|_ literal) in source",
   688  	}, {
   689  		value: `"str"`,
   690  		err:   "cannot use value \"str\" (type string) as bool",
   691  	}, {
   692  		value: `true`,
   693  		bool:  true,
   694  	}, {
   695  		value: `false`,
   696  	}, {
   697  		value: `bool`,
   698  		err:   "non-concrete value bool",
   699  	}}
   700  	for _, tc := range testCases {
   701  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   702  			got, err := getValue(t, tc.value).Bool()
   703  			if checkErr(t.T, err, tc.err, "init") {
   704  				if got != tc.bool {
   705  					t.Errorf("got %v; want %v", got, tc.bool)
   706  				}
   707  			}
   708  		})
   709  	}
   710  }
   711  
   712  func TestList(t *testing.T) {
   713  	testCases := []struct {
   714  		value string
   715  		res   string
   716  		err   string
   717  	}{{
   718  		value: `_|_`,
   719  		err:   "explicit error (_|_ literal) in source",
   720  	}, {
   721  		value: `"str"`,
   722  		err:   "cannot use value \"str\" (type string) as list",
   723  	}, {
   724  		value: `[]`,
   725  		res:   "[]",
   726  	}, {
   727  		value: `[1,2,3]`,
   728  		res:   "[1,2,3,]",
   729  	}, {
   730  		value: `[for x in #y if x > 1 { x }]
   731  		#y: [1,2,3]`,
   732  		res: "[2,3,]",
   733  	}, {
   734  		value: `[int]`,
   735  		err:   "cannot convert incomplete value",
   736  	}}
   737  	for _, tc := range testCases {
   738  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   739  			l, err := getValue(t, tc.value).List()
   740  			checkFatal(t.T, err, tc.err, "init")
   741  
   742  			buf := []byte{'['}
   743  			for wantIdx := 0; l.Next(); wantIdx++ {
   744  				// Ensure that we can get each index as well.
   745  				if got := l.Selector().Index(); got != wantIdx {
   746  					t.Errorf("Index got %v; want %v", got, wantIdx)
   747  				}
   748  				b, err := l.Value().MarshalJSON()
   749  				checkFatal(t.T, err, tc.err, "list.Value")
   750  				buf = append(buf, b...)
   751  				buf = append(buf, ',')
   752  			}
   753  			buf = append(buf, ']')
   754  			if got := string(buf); got != tc.res {
   755  				t.Errorf("got %v; want %v", got, tc.res)
   756  			}
   757  		})
   758  	}
   759  }
   760  
   761  func TestFields(t *testing.T) {
   762  	testCases := []struct {
   763  		value string
   764  		res   string
   765  		err   string
   766  		opts  []cue.Option
   767  
   768  		todoV3 bool
   769  	}{{
   770  		value: `{ #def: 1, _hidden: 2, opt?: 3, reg: 4 }`,
   771  		res:   "{reg:4,}",
   772  	}, {
   773  		value: `_|_`,
   774  		err:   "explicit error (_|_ literal) in source",
   775  	}, {
   776  		value: `"str"`,
   777  		err:   "cannot use value \"str\" (type string) as struct",
   778  	}, {
   779  		value: `{}`,
   780  		res:   "{}",
   781  	}, {
   782  		value: `{a:1,b:2,c:3}`,
   783  		res:   "{a:1,b:2,c:3,}",
   784  	}, {
   785  		value: `{a:1,"_b":2,c:3,_d:4}`,
   786  		res:   `{a:1,"_b":2,c:3,}`,
   787  	}, {
   788  		value: `{_a:"a"}`,
   789  		res:   "{}",
   790  	}, {
   791  		value: `{ for k, v in #y if v > 1 {"\(k)": v} }
   792  			#y: {a:1,b:2,c:3}`,
   793  		res: "{b:2,c:3,}",
   794  	}, {
   795  		value: `{ #def: 1, _hidden: 2, opt?: 3, reg: 4 }`,
   796  		res:   "{reg:4,}",
   797  	}, {
   798  		value: `{a:1,b:2,c:int}`,
   799  		err:   "cannot convert incomplete value",
   800  	}, {
   801  		value: `
   802  		step1: {}
   803  		step2: {prefix: 3}
   804  		if step2.value > 100 {
   805  		   step3: {prefix: step2.value}
   806  		}
   807  		_hidden: 3`,
   808  		res: `{step1:{},step2:{"prefix":3},}`,
   809  	}, {
   810  		opts: []cue.Option{cue.Final()},
   811  		value: `
   812  		step1: {}
   813  		if step1.value > 100 {
   814  		}`,
   815  		err: "undefined field: value",
   816  	}, {
   817  		opts: []cue.Option{cue.Concrete(true)},
   818  		value: `
   819  		step1: {}
   820  		if step1.value > 100 {
   821  		}`,
   822  		err: "undefined field: value",
   823  	}, {
   824  		value: `{a!: 1, b?: 2, c: 3}`,
   825  		err:   "a: field is required but not present",
   826  	}, {
   827  		opts:  []cue.Option{cue.Hidden(true)},
   828  		value: `1, _a: 2`,
   829  		res:   `{_a:2,}`,
   830  	}, {
   831  		opts:  []cue.Option{cue.Definitions(true)},
   832  		value: `1, #a: 2`,
   833  		res:   `{#a:2,}`,
   834  	}, {
   835  		opts:  []cue.Option{cue.Optional(true)},
   836  		value: `1, a?: 2`,
   837  		err:   "cannot use value 1 (type int) as struct",
   838  	}}
   839  	for _, tc := range testCases {
   840  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   841  			obj := getValue(t, tc.value)
   842  
   843  			iter, err := obj.Fields(tc.opts...)
   844  			checkFatal(t.T, err, tc.err, "init")
   845  
   846  			buf := []byte{'{'}
   847  			for iter.Next() {
   848  				buf = append(buf, iter.Selector().String()...)
   849  				buf = append(buf, ':')
   850  				b, err := iter.Value().MarshalJSON()
   851  				checkFatal(t.T, err, tc.err, "Obj.At")
   852  				buf = append(buf, b...)
   853  				buf = append(buf, ',')
   854  			}
   855  			buf = append(buf, '}')
   856  			if got := string(buf); got != tc.res {
   857  				t.Errorf("got %v; want %v", got, tc.res)
   858  			}
   859  
   860  			iter, _ = obj.Fields(tc.opts...)
   861  			for iter.Next() {
   862  				want, err := iter.Value().MarshalJSON()
   863  				checkFatal(t.T, err, tc.err, "Obj.At2")
   864  
   865  				got, err := obj.LookupPath(cue.MakePath(iter.Selector())).MarshalJSON()
   866  				checkFatal(t.T, err, tc.err, "Obj.At2")
   867  
   868  				if !bytes.Equal(got, want) {
   869  					t.Errorf("Lookup: got %q; want %q", got, want)
   870  				}
   871  			}
   872  			v := obj.LookupPath(cue.MakePath(cue.Str("non-existing")))
   873  			checkErr(t.T, v.Err(), "not found", "non-existing")
   874  		})
   875  	}
   876  }
   877  
   878  func TestAllFields(t *testing.T) {
   879  	testCases := []struct {
   880  		value string
   881  		res   string
   882  		err   string
   883  	}{{
   884  		value: `{a:1,"_b":2,c:3,_d:4}`,
   885  		res:   `{a:1,"_b":2,c:3,_d:4,}`,
   886  	}, {
   887  		value: `{_a:"a"}`,
   888  		res:   `{_a:"a",}`,
   889  	}, {
   890  		value: `{_a:"a", b?: "b", #c: 3}`,
   891  		res:   `{_a:"a",b?:"b",#c:3,}`,
   892  	}, {
   893  		// Issue #1879
   894  		value: `{a: 1, if false { b: 2 }}`,
   895  		res:   `{a:1,}`,
   896  	}, {
   897  		value: `{a!:1,b?:2,c:3}`,
   898  		res:   `{a!:1,b?:2,c:3,}`,
   899  	}}
   900  	for _, tc := range testCases {
   901  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   902  			obj := getValue(t, tc.value)
   903  
   904  			var iter *cue.Iterator // Verify that the returned iterator is a pointer.
   905  			iter, err := obj.Fields(cue.All())
   906  			checkFatal(t.T, err, tc.err, "init")
   907  
   908  			buf := []byte{'{'}
   909  			for iter.Next() {
   910  				buf = append(buf, iter.Selector().String()...)
   911  				buf = append(buf, ':')
   912  				b, err := iter.Value().MarshalJSON()
   913  				checkFatal(t.T, err, tc.err, "Obj.At")
   914  				buf = append(buf, b...)
   915  				buf = append(buf, ',')
   916  			}
   917  			buf = append(buf, '}')
   918  			if got := string(buf); got != tc.res {
   919  				t.Errorf("got %v; want %v", got, tc.res)
   920  			}
   921  		})
   922  	}
   923  }
   924  
   925  func TestFieldType(t *testing.T) {
   926  	testCases := []struct {
   927  		value string
   928  		want  string
   929  	}{{
   930  		value: `{a:1,"_b":2,c:3,_d:4,#def: 1}`,
   931  		want: `
   932  		StringLabel
   933  		StringLabel
   934  		StringLabel
   935  		HiddenLabel
   936  		DefinitionLabel`,
   937  	}, {
   938  		value: `{a!:1,b?:2,c:3}`,
   939  		want: `
   940  		StringLabel|RequiredConstraint
   941  		StringLabel|OptionalConstraint
   942  		StringLabel`,
   943  	}}
   944  	for _, tc := range testCases {
   945  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
   946  			obj := getValue(t, tc.value)
   947  
   948  			iter, err := obj.Fields(cue.All())
   949  			if err != nil {
   950  				t.Fatal(err)
   951  			}
   952  
   953  			b := &strings.Builder{}
   954  			for iter.Next() {
   955  				fmt.Fprint(b, "\n\t\t", iter.FieldType())
   956  			}
   957  			if got := b.String(); got != tc.want {
   958  				t.Errorf("got:%v\nwant:%v", got, tc.want)
   959  			}
   960  		})
   961  	}
   962  }
   963  
   964  func TestLookup(t *testing.T) {
   965  	cuetdtest.FullMatrix.Do(t, func(t *cuetdtest.M) {
   966  		ctx := t.Context()
   967  		val := mustCompile(t, ctx, `
   968  #V: {
   969  	x: int
   970  }
   971  #X: {
   972  	[string]: int64
   973  } & #V
   974  v: #X
   975  
   976  a: {
   977  	b!: 1
   978  	c: 2
   979  }`)
   980  		// expr, err := parser.ParseExpr("lookup.cue", `v`, parser.DeclarationErrors, parser.AllErrors)
   981  		// if err != nil {
   982  		// 	log.Fatalf("parseExpr: %v", err)
   983  		// }
   984  		// v := inst.Eval(expr)
   985  
   986  		type testCase struct {
   987  			ref    []string
   988  			result string
   989  			syntax string
   990  		}
   991  		testCases := []testCase{{
   992  			ref: []string{"a"},
   993  			result: `{
   994  	b!: 1
   995  	c:  2
   996  }`,
   997  			syntax: "{b!: 1, c: 2}",
   998  		}, {
   999  			// Allow descending into structs even if it has a required field error.
  1000  			ref:    []string{"a", "c"},
  1001  			result: "2",
  1002  			syntax: "2",
  1003  		}, {
  1004  			ref:    []string{"a", "b"},
  1005  			result: "_|_ // a.b: field is required but not present",
  1006  			syntax: "1",
  1007  		}, {
  1008  			ref:    []string{"v", "x"},
  1009  			result: "int64",
  1010  			syntax: "int64",
  1011  		}}
  1012  		for _, tc := range testCases {
  1013  			t.Run("", func(t *testing.T) {
  1014  				v := val.Lookup(tc.ref...)
  1015  
  1016  				if got := fmt.Sprintf("%+v", v); got != tc.result {
  1017  					t.Errorf("got %v; want %v", got, tc.result)
  1018  				}
  1019  
  1020  				got := fmt.Sprint(astinternal.DebugStr(v.Eval().Syntax()))
  1021  				if got != tc.syntax {
  1022  					t.Errorf("got %v; want %v", got, tc.syntax)
  1023  				}
  1024  
  1025  				v = val.Lookup()
  1026  				for _, ref := range tc.ref {
  1027  					s, err := v.Struct()
  1028  					if err != nil {
  1029  						t.Fatal(err)
  1030  					}
  1031  					fi, err := s.FieldByName(ref, false)
  1032  					if err != nil {
  1033  						t.Fatal(err)
  1034  					}
  1035  					v = fi.Value
  1036  
  1037  					// Struct gets all fields. Skip tests with optional fields,
  1038  					// as the result will differ.
  1039  					if cue.ValueVertex(v).ArcType != adt.ArcMember {
  1040  						return
  1041  					}
  1042  				}
  1043  
  1044  				if got := fmt.Sprintf("%+v", v); got != tc.result {
  1045  					t.Errorf("got %v; want %v", got, tc.result)
  1046  				}
  1047  
  1048  				got = fmt.Sprint(astinternal.DebugStr(v.Eval().Syntax()))
  1049  				if got != tc.syntax {
  1050  					t.Errorf("got %v; want %v", got, tc.syntax)
  1051  				}
  1052  			})
  1053  		}
  1054  	})
  1055  }
  1056  
  1057  func goValue(v cue.Value) interface{} {
  1058  	var x interface{}
  1059  	err := v.Decode(&x)
  1060  	if err != nil {
  1061  		return err
  1062  	}
  1063  	return x
  1064  }
  1065  
  1066  // TODO: Exporting of Vertex as Conjunct
  1067  func TestFill(t *testing.T) {
  1068  	// TODO: run with matrix.
  1069  
  1070  	ctx := cuecontext.New()
  1071  
  1072  	val := ctx.BuildExpr(ast.NewStruct("bar", ast.NewString("baz")))
  1073  	if err := val.Err(); err != nil {
  1074  		t.Fatal(err)
  1075  	}
  1076  
  1077  	testCases := []struct {
  1078  		in   string
  1079  		x    interface{}
  1080  		path string // comma-separated path
  1081  		out  string
  1082  	}{{
  1083  		in: `
  1084  		foo: int
  1085  		bar: foo
  1086  		`,
  1087  		x:    3,
  1088  		path: "foo",
  1089  		out: `
  1090  		foo: 3
  1091  		bar: 3
  1092  		`,
  1093  	}, {
  1094  		in: `
  1095  		string
  1096  		`,
  1097  		x:    "foo",
  1098  		path: "",
  1099  		out: `
  1100  		"foo"
  1101  		`,
  1102  	}, {
  1103  		in: `
  1104  		foo: _
  1105  		`,
  1106  		x:    val,
  1107  		path: "foo",
  1108  		out: `
  1109  		{foo: {bar: "baz"}}
  1110  		`,
  1111  	}}
  1112  
  1113  	for _, tc := range testCases {
  1114  		var path []string
  1115  		if tc.path != "" {
  1116  			path = strings.Split(tc.path, ",")
  1117  		}
  1118  
  1119  		v := mustCompile(t, ctx, tc.in)
  1120  		v = v.Fill(tc.x, path...)
  1121  
  1122  		w := mustCompile(t, ctx, tc.out)
  1123  
  1124  		if diff := cmp.Diff(goValue(v), goValue(w)); diff != "" {
  1125  			t.Error(diff)
  1126  			t.Errorf("\ngot:  %s\nwant: %s", v, w)
  1127  		}
  1128  	}
  1129  }
  1130  
  1131  func TestFill2(t *testing.T) {
  1132  	// TODO: run with matrix.
  1133  
  1134  	ctx := cuecontext.New()
  1135  
  1136  	root := mustCompile(t, ctx, `
  1137  	#Provider: {
  1138  		ID: string
  1139  		notConcrete: bool
  1140  		a: int
  1141  		b: int
  1142  	}
  1143  	`)
  1144  
  1145  	spec := root.LookupDef("#Provider")
  1146  	providerInstance := spec.Fill("12345", "ID")
  1147  	root = root.Fill(providerInstance, "providers", "myprovider")
  1148  
  1149  	got := fmt.Sprintf("%#v", root)
  1150  	want := `#Provider: {
  1151  	ID:          string
  1152  	notConcrete: bool
  1153  	a:           int
  1154  	b:           int
  1155  }
  1156  providers: {
  1157  	myprovider: {
  1158  		ID:          "12345"
  1159  		notConcrete: bool
  1160  		a:           int
  1161  		b:           int
  1162  	}
  1163  }`
  1164  	if got != want {
  1165  		t.Errorf("got:  %s\nwant: %s", got, want)
  1166  	}
  1167  }
  1168  
  1169  func TestFillPath(t *testing.T) {
  1170  	cuetdtest.FullMatrix.Do(t, func(t *cuetdtest.M) {
  1171  		ctx := t.Context()
  1172  
  1173  		val := ctx.BuildExpr(ast.NewStruct("bar", ast.NewString("baz")))
  1174  		if err := val.Err(); err != nil {
  1175  			t.Fatal(err)
  1176  		}
  1177  
  1178  		testCases := []struct {
  1179  			in   string
  1180  			x    interface{}
  1181  			path cue.Path
  1182  			out  string
  1183  		}{{
  1184  			in: `
  1185  		foo: int
  1186  		bar: foo
  1187  		`,
  1188  			x:    3,
  1189  			path: cue.ParsePath("foo"),
  1190  			out: `
  1191  		foo: 3
  1192  		bar: 3
  1193  		`,
  1194  		}, {
  1195  			in: `
  1196  		X="#foo": int
  1197  		bar: X
  1198  		`,
  1199  			x:    3,
  1200  			path: cue.ParsePath(`"#foo"`),
  1201  			out: `
  1202  		"#foo": 3
  1203  		bar: 3
  1204  		`,
  1205  		}, {
  1206  			in: `
  1207  		X="#foo": foo: int
  1208  		bar: X.foo
  1209  		`,
  1210  			x:    3,
  1211  			path: cue.ParsePath(`"#foo".foo`),
  1212  			out: `
  1213  		"#foo": foo: 3
  1214  		bar: 3
  1215  		`,
  1216  		}, {
  1217  			in: `
  1218  		foo: #foo: int
  1219  		bar: foo.#foo
  1220  		`,
  1221  			x:    3,
  1222  			path: cue.ParsePath("foo.#foo"),
  1223  			out: `
  1224  		foo: {
  1225  			#foo: 3
  1226  		}
  1227  		bar: 3
  1228  		`,
  1229  		}, {
  1230  			in: `
  1231  		foo: _foo: int
  1232  		bar: foo._foo
  1233  		`,
  1234  			x:    3,
  1235  			path: cue.MakePath(cue.Str("foo"), cue.Hid("_foo", "_")),
  1236  			out: `
  1237  		foo: {
  1238  			_foo: 3
  1239  		}
  1240  		bar: 3
  1241  		`,
  1242  		}, {
  1243  			in: `
  1244  		string
  1245  		`,
  1246  			x:    "foo",
  1247  			path: cue.ParsePath(""),
  1248  			out: `
  1249  		"foo"
  1250  		`,
  1251  		}, {
  1252  			in: `
  1253  		foo: _
  1254  		`,
  1255  			x:    val,
  1256  			path: cue.ParsePath("foo"),
  1257  			out: `
  1258  		{foo: {bar: "baz"}}
  1259  		`,
  1260  		}, {
  1261  			// Resolve to enclosing
  1262  			in: `
  1263  		foo: _
  1264  		x: 1
  1265  		`,
  1266  			x:    ast.NewIdent("x"),
  1267  			path: cue.ParsePath("foo"),
  1268  			out: `
  1269  		{foo: 1, x: 1}
  1270  		`,
  1271  		}, {
  1272  			in: `
  1273  		foo: {
  1274  			bar: _
  1275  			x: 1
  1276  		}
  1277  		`,
  1278  			x:    ast.NewIdent("x"),
  1279  			path: cue.ParsePath("foo.bar"),
  1280  			out: `
  1281  		{foo: {bar: 1, x: 1}}
  1282  		`,
  1283  		}, {
  1284  			// Resolve one scope up
  1285  			in: `
  1286  		x: 1
  1287  		foo: {
  1288  			bar: _
  1289  		}
  1290  		`,
  1291  			x:    ast.NewIdent("x"),
  1292  			path: cue.ParsePath("foo.bar"),
  1293  			out: `
  1294  		{foo: {bar: 1}, x: 1}
  1295  		`,
  1296  		}, {
  1297  			// Resolve within ast expression
  1298  			in: `
  1299  		foo: {
  1300  			bar: _
  1301  		}
  1302  		`,
  1303  			x: ast.NewStruct(
  1304  				ast.NewIdent("x"), ast.NewString("1"),
  1305  				ast.NewIdent("y"), ast.NewIdent("x"),
  1306  			),
  1307  			path: cue.ParsePath("foo.bar"),
  1308  			out: `
  1309  			{foo: {bar: {x: "1", y: "1"}}}
  1310  			`,
  1311  		}, {
  1312  			// Resolve in non-existing
  1313  			in: `
  1314  		foo: x: 1
  1315  		`,
  1316  			x:    ast.NewIdent("x"),
  1317  			path: cue.ParsePath("foo.bar.baz"),
  1318  			out: `
  1319  		{foo: {x: 1, bar: baz: 1}}
  1320  		`,
  1321  		}, {
  1322  			// empty path
  1323  			in: `
  1324  		_
  1325  		#foo: 1
  1326  		`,
  1327  			x:   ast.NewIdent("#foo"),
  1328  			out: `{1, #foo: 1}`,
  1329  		}, {
  1330  			in:   `[...int]`,
  1331  			x:    1,
  1332  			path: cue.ParsePath("0"),
  1333  			out:  `[1]`,
  1334  		}, {
  1335  			in:   `[1, ...int]`,
  1336  			x:    1,
  1337  			path: cue.ParsePath("1"),
  1338  			out:  `[1, 1]`,
  1339  		}, {
  1340  			in:   `a: {b: v: int, c: v: int}`,
  1341  			x:    1,
  1342  			path: cue.MakePath(cue.Str("a"), cue.AnyString, cue.Str("v")),
  1343  			out: `{
  1344  	a: {
  1345  		b: {
  1346  			v: 1
  1347  		}
  1348  		c: {
  1349  			v: 1
  1350  		}
  1351  	}
  1352  }`,
  1353  		}, {
  1354  			in:   `a: [_]`,
  1355  			x:    1,
  1356  			path: cue.MakePath(cue.Str("a"), cue.AnyIndex, cue.Str("b")),
  1357  			out: `{
  1358  	a: [{
  1359  		b: 1
  1360  	}]
  1361  }`,
  1362  		}, {
  1363  			in:   `a: 1`,
  1364  			x:    1,
  1365  			path: cue.MakePath(cue.Str("b").Optional()),
  1366  			out:  `{a: 1}`,
  1367  		}, {
  1368  			in:   `b: int`,
  1369  			x:    1,
  1370  			path: cue.MakePath(cue.Str("b").Optional()),
  1371  			out:  `{b: 1}`,
  1372  		}}
  1373  
  1374  		for _, tc := range testCases {
  1375  			t.Run("", func(t *testing.T) {
  1376  				v := mustCompile(t, ctx, tc.in)
  1377  				v = v.FillPath(tc.path, tc.x)
  1378  
  1379  				w := mustCompile(t, ctx, tc.out)
  1380  
  1381  				if diff := cmp.Diff(goValue(v), goValue(w)); diff != "" {
  1382  					t.Error(diff)
  1383  					t.Error(cmp.Diff(goValue(v), goValue(w)))
  1384  					t.Errorf("\ngot:  %s\nwant: %s", v, w)
  1385  				}
  1386  			})
  1387  		}
  1388  	})
  1389  }
  1390  
  1391  func TestFillPathError(t *testing.T) {
  1392  	testCases := []struct {
  1393  		in   string
  1394  		x    interface{}
  1395  		path cue.Path
  1396  		err  string
  1397  	}{{
  1398  		// unsupported type.
  1399  		in:  `_`,
  1400  		x:   make(chan int),
  1401  		err: "unsupported Go type (chan int)",
  1402  	}}
  1403  
  1404  	for _, tc := range testCases {
  1405  		cuetdtest.FullMatrix.Run(t, "", func(t *cuetdtest.M) {
  1406  			ctx := t.Context()
  1407  			v := mustCompile(t, ctx, tc.in)
  1408  			v = v.FillPath(tc.path, tc.x)
  1409  
  1410  			err := v.Err()
  1411  			if err == nil {
  1412  				t.Errorf("unexpected success")
  1413  
  1414  			} else if got := err.Error(); !strings.Contains(got, tc.err) {
  1415  				t.Errorf("\ngot:  %s\nwant: %s", got, tc.err)
  1416  			}
  1417  		})
  1418  	}
  1419  }
  1420  
  1421  func TestAllows(t *testing.T) {
  1422  	testCases := []struct {
  1423  		desc  string
  1424  		in    string
  1425  		sel   cue.Selector
  1426  		allow bool
  1427  
  1428  		todo_nosharing bool
  1429  	}{{
  1430  		desc: "allow new field in open struct",
  1431  		in: `
  1432  		x: {
  1433  			a: int
  1434  		}
  1435  		`,
  1436  		sel:   cue.Str("b"),
  1437  		allow: true,
  1438  	}, {
  1439  		desc: "disallow new field in definition",
  1440  		in: `
  1441  		x: #Def
  1442  		#Def: {
  1443  			a: int
  1444  		}
  1445  		`,
  1446  		sel: cue.Str("b"),
  1447  	}, {
  1448  		desc: "disallow new field in explicitly closed struct",
  1449  		in: `
  1450  		x: close({
  1451  			a: int
  1452  		})
  1453  		`,
  1454  		sel: cue.Str("b"),
  1455  	}, {
  1456  		desc: "allow field in pattern",
  1457  		in: `
  1458  				x: #X
  1459  				#X: [>"a"]: 1
  1460  				`,
  1461  		sel:   cue.Str("b"),
  1462  		allow: true,
  1463  	}, {
  1464  		desc: "allow index in open list",
  1465  		in: `
  1466  		x: [...int]
  1467  		`,
  1468  		sel:   cue.Index(100),
  1469  		allow: true,
  1470  	}, {
  1471  		desc: "disallow index in closed list",
  1472  		in: `
  1473  		x: []
  1474  		`,
  1475  		sel: cue.Index(0),
  1476  	}, {
  1477  		desc: "allow existing index in closed list",
  1478  		in: `
  1479  		x: [1]
  1480  		`,
  1481  		sel:   cue.Index(0),
  1482  		allow: true,
  1483  	}, {
  1484  		desc: "definition in non-def closed list",
  1485  		in: `
  1486  		x: [1]
  1487  		`,
  1488  		sel:   cue.Def("#foo"),
  1489  		allow: true,
  1490  	}, {
  1491  		// TODO(disallow)
  1492  		desc: "definition in def open list",
  1493  		in: `
  1494  		x: #Def
  1495  		x: [1]
  1496  		#Def: [...int]
  1497  		`,
  1498  		sel:   cue.Def("#foo"),
  1499  		allow: true,
  1500  	}, {
  1501  		desc: "field in def open list",
  1502  		in: `
  1503  		x: #Def
  1504  		x: [1]
  1505  		#Def: [...int]
  1506  		`,
  1507  		sel: cue.Str("foo"),
  1508  	}, {
  1509  		desc: "definition in open scalar",
  1510  		in: `
  1511  		x: 1
  1512  		`,
  1513  		sel:   cue.Def("#foo"),
  1514  		allow: true,
  1515  	}, {
  1516  		desc: "field in scalar",
  1517  		in: `
  1518  		x: #Def
  1519  		x: 1
  1520  		#Def: int
  1521  		`,
  1522  		sel: cue.Str("foo"),
  1523  	}, {
  1524  		desc: "any index in closed list",
  1525  		in: `
  1526  		x: [1]
  1527  		`,
  1528  		sel: cue.AnyIndex,
  1529  	}, {
  1530  		desc: "any index in open list",
  1531  		in: `
  1532  		x: [...int]
  1533  			`,
  1534  		sel:   cue.AnyIndex,
  1535  		allow: true,
  1536  	}, {
  1537  		desc: "definition in open scalar",
  1538  		in: `
  1539  		x: 1
  1540  		`,
  1541  		sel:   cue.AnyDefinition,
  1542  		allow: true,
  1543  	}, {
  1544  		desc: "field in open scalar",
  1545  		in: `
  1546  			x: 1
  1547  			`,
  1548  		sel: cue.AnyString,
  1549  
  1550  		// TODO(v0.6.0)
  1551  		// }, {
  1552  		// 	desc: "definition in closed scalar",
  1553  		// 	in: `
  1554  		// 	x: #Def
  1555  		// 	x: 1
  1556  		// 	#Def: int
  1557  		// 	`,
  1558  		// 	sel:   cue.AnyDefinition,
  1559  		// 	allow: true,
  1560  	}, {
  1561  		desc: "allow field in any",
  1562  		in: `
  1563  			x: _
  1564  			`,
  1565  		sel:   cue.AnyString,
  1566  		allow: true,
  1567  	}, {
  1568  		desc: "allow index in any",
  1569  		in: `
  1570  		x: _
  1571  		`,
  1572  		sel:   cue.AnyIndex,
  1573  		allow: true,
  1574  	}, {
  1575  		desc: "allow index in disjunction",
  1576  		in: `
  1577  		x: [...int] | 1
  1578  		`,
  1579  		sel:   cue.AnyIndex,
  1580  		allow: true,
  1581  	}, {
  1582  		desc: "allow index in disjunction",
  1583  		in: `
  1584  		x: [] | [...int]
  1585  			`,
  1586  		sel:   cue.AnyIndex,
  1587  		allow: true,
  1588  	}, {
  1589  		desc: "disallow index in disjunction",
  1590  		in: `
  1591  		x: [1, 2] | [3, 2]
  1592  		`,
  1593  		sel: cue.AnyIndex,
  1594  	}, {
  1595  		desc: "disallow index in non-list disjunction",
  1596  		in: `
  1597  		x: "foo" | 1
  1598  		`,
  1599  		sel: cue.AnyIndex,
  1600  	}, {
  1601  		desc: "allow label in disjunction",
  1602  		in: `
  1603  		x: {} | 1
  1604  		`,
  1605  		sel:   cue.AnyString,
  1606  		allow: true,
  1607  	}, {
  1608  		desc: "allow label in disjunction",
  1609  		in: `
  1610  		x: #Def
  1611  		#Def: { a: 1 } | { b: 1, ... }
  1612  		`,
  1613  		sel:   cue.AnyString,
  1614  		allow: true,
  1615  
  1616  		todo_nosharing: true,
  1617  	}, {
  1618  		desc: "disallow label in disjunction",
  1619  		in: `
  1620  		x: #Def
  1621  		#Def: { a: 1 } | { b: 1 }
  1622  		`,
  1623  		sel: cue.AnyString,
  1624  	}, {
  1625  		desc: "pattern constraint",
  1626  		in: `
  1627  		x: #PC
  1628  		#PC: [>"m"]: int
  1629  		`,
  1630  		sel: cue.Str(""),
  1631  	}, {
  1632  		desc: "pattern constraint",
  1633  		in: `
  1634  		x: #PC
  1635  		#PC: [>"m"]: int
  1636  		`,
  1637  		sel:   cue.Str("z"),
  1638  		allow: true,
  1639  	}, {
  1640  		desc: "any in pattern constraint",
  1641  		in: `
  1642  		x: #PC
  1643  		#PC: [>"m"]: int
  1644  		`,
  1645  		sel: cue.AnyString,
  1646  	}, {
  1647  		desc: "any in pattern constraint",
  1648  		in: `
  1649  		x: #PC
  1650  		#PC: [>" "]: int
  1651  		`,
  1652  		sel: cue.AnyString,
  1653  	}}
  1654  
  1655  	path := cue.ParsePath("x")
  1656  
  1657  	for _, tc := range testCases {
  1658  		cuetdtest.FullMatrix.Run(t, tc.desc, func(t *cuetdtest.M) {
  1659  			if tc.todo_nosharing {
  1660  				t.TODO_NoSharing()
  1661  			}
  1662  			ctx := t.Context()
  1663  			v := mustCompile(t, ctx, tc.in)
  1664  			v = v.LookupPath(path)
  1665  
  1666  			got := v.Allows(tc.sel)
  1667  			if got != tc.allow {
  1668  				t.Errorf("got %v; want %v", got, tc.allow)
  1669  			}
  1670  		})
  1671  	}
  1672  }
  1673  
  1674  func TestFillFloat(t *testing.T) {
  1675  	// This tests panics for issue #749
  1676  
  1677  	want := `{
  1678  	x: 3.14
  1679  }`
  1680  
  1681  	filltest := func(x interface{}) {
  1682  		ctx := cuecontext.New()
  1683  		val := mustCompile(t, ctx, `
  1684  	x: number
  1685  	`)
  1686  		val = val.Fill(x, "x")
  1687  
  1688  		got := fmt.Sprint(val)
  1689  		if got != want {
  1690  			t.Errorf("got:  %s\nwant: %s", got, want)
  1691  		}
  1692  	}
  1693  
  1694  	filltest(float32(3.14))
  1695  	filltest(float64(3.14))
  1696  	filltest(big.NewFloat(3.14))
  1697  }
  1698  
  1699  func TestValue_LookupDef(t *testing.T) {
  1700  	testCases := []struct {
  1701  		in     string
  1702  		def    string // comma-separated path
  1703  		exists bool
  1704  		out    string
  1705  	}{{
  1706  		in:  `#foo: 3`,
  1707  		def: "#foo",
  1708  		out: `3`,
  1709  	}, {
  1710  		in:  `_foo: 3`,
  1711  		def: "_foo",
  1712  		out: `_|_ // field not found: #_foo`,
  1713  	}, {
  1714  		in:  `_#foo: 3`,
  1715  		def: "_#foo",
  1716  		out: `_|_ // field not found: _#foo`,
  1717  	}, {
  1718  		in:  `"foo", #foo: 3`,
  1719  		def: "#foo",
  1720  		out: `3`,
  1721  	}}
  1722  
  1723  	for _, tc := range testCases {
  1724  		cuetdtest.FullMatrix.Run(t, tc.def, func(t *cuetdtest.M) {
  1725  			ctx := t.Context()
  1726  			v := mustCompile(t, ctx, tc.in)
  1727  			v = v.LookupDef(tc.def)
  1728  			got := fmt.Sprint(v)
  1729  
  1730  			if got != tc.out {
  1731  				t.Errorf("\ngot:  %s\nwant: %s", got, tc.out)
  1732  			}
  1733  		})
  1734  	}
  1735  }
  1736  
  1737  // TODO: trim down to individual defaults?
  1738  func TestDefaults(t *testing.T) {
  1739  	testCases := []struct {
  1740  		value string
  1741  		def   string
  1742  		val   string
  1743  		ok    bool
  1744  	}{{
  1745  		value: `number | *1`,
  1746  		def:   "1",
  1747  		val:   "number",
  1748  		ok:    true,
  1749  	}, {
  1750  		value: `1 | 2 | *3`,
  1751  		def:   "3",
  1752  		val:   "1|2|3",
  1753  		ok:    true,
  1754  	}, {
  1755  		value: `*{a:1,b:2}|{a:1}|{b:2}`,
  1756  		def:   "{a:1,b:2}",
  1757  		val:   "{a: 1}|{b: 2}",
  1758  		ok:    true,
  1759  	}, {
  1760  		value: `{a:1}&{b:2}`,
  1761  		def:   `{a:1,b:2}`,
  1762  		val:   ``,
  1763  		ok:    false,
  1764  	}, {
  1765  		value: `*_|_ | (*"x" | string)`,
  1766  		def:   `"x" | string`,
  1767  		val:   `"x"|string`,
  1768  		ok:    false,
  1769  	}}
  1770  	for _, tc := range testCases {
  1771  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
  1772  			v := getValue(t, "a: "+tc.value).Lookup("a")
  1773  
  1774  			v = v.Eval()
  1775  			d, ok := v.Default()
  1776  			if ok != tc.ok {
  1777  				t.Errorf("hasDefault: got %v; want %v", ok, tc.ok)
  1778  			}
  1779  
  1780  			if got := compactRawStr(d); got != tc.def {
  1781  				t.Errorf("default: got %v; want %v", got, tc.def)
  1782  			}
  1783  
  1784  			op, val := d.Expr()
  1785  			if op != cue.OrOp {
  1786  				return
  1787  			}
  1788  			vars := []string{}
  1789  			for _, v := range val {
  1790  				vars = append(vars, fmt.Sprint(v))
  1791  			}
  1792  			if got := strings.Join(vars, "|"); got != tc.val {
  1793  				t.Errorf("value: got %v; want %v", got, tc.val)
  1794  			}
  1795  		})
  1796  	}
  1797  }
  1798  
  1799  func TestLen(t *testing.T) {
  1800  	testCases := []struct {
  1801  		input  string
  1802  		length string
  1803  	}{{
  1804  		input:  "[1, 3]",
  1805  		length: "2",
  1806  	}, {
  1807  		input:  "[1, 3, ...]",
  1808  		length: "int & >=2",
  1809  	}, {
  1810  		input:  `"foo"`,
  1811  		length: "3",
  1812  	}, {
  1813  		input:  `'foo'`,
  1814  		length: "3",
  1815  		// TODO: Currently not supported.
  1816  		// }, {
  1817  		// 	input:  "{a:1, b:3, a:1, c?: 3, _hidden: 4}",
  1818  		// 	length: "2",
  1819  	}, {
  1820  		input:  "3",
  1821  		length: "_|_ // len not supported for type int",
  1822  	}}
  1823  	for _, tc := range testCases {
  1824  		cuetdtest.FullMatrix.Run(t, tc.input, func(t *cuetdtest.M) {
  1825  			v := getValue(t, "a: "+tc.input).Lookup("a")
  1826  
  1827  			length := v.Len()
  1828  			if got := fmt.Sprint(length); got != tc.length {
  1829  				t.Errorf("length: got %v; want %v", got, tc.length)
  1830  			}
  1831  		})
  1832  	}
  1833  }
  1834  
  1835  func TestTemplate(t *testing.T) {
  1836  	testCases := []struct {
  1837  		value string
  1838  		path  []string
  1839  		want  string
  1840  
  1841  		skip bool
  1842  	}{{
  1843  		value: `
  1844  		a: [Name=string]: Name
  1845  		`,
  1846  		path: []string{"a", ""},
  1847  		want: `"label"`,
  1848  	}, {
  1849  		value: `
  1850  		[Name=string]: { a: Name }
  1851  		`,
  1852  		path: []string{"", "a"},
  1853  		want: `"label"`,
  1854  	}, {
  1855  		value: `
  1856  		[Name=string]: { a: Name }
  1857  		`,
  1858  		path: []string{""},
  1859  		want: `{"a":"label"}`,
  1860  	}, {
  1861  		value: `
  1862  		a: [Foo=string]: [Bar=string]: { b: Foo+Bar }
  1863  		`,
  1864  		path: []string{"a", "", ""},
  1865  		want: `{"b":"labellabel"}`,
  1866  	}, {
  1867  		value: `
  1868  		a: [Foo=string]: b: [Bar=string]: { c: Foo+Bar }
  1869  		a: foo: b: [Bar=string]: { d: Bar }
  1870  		`,
  1871  		path: []string{"a", "foo", "b", ""},
  1872  		want: `{"c":"foolabel","d":"label"}`,
  1873  
  1874  		skip: true, // TODO: reordering
  1875  	}}
  1876  	for _, tc := range testCases {
  1877  		cuetdtest.FullMatrix.Run(t, "", func(t *cuetdtest.M) {
  1878  			if tc.skip {
  1879  				t.TODO_V3()
  1880  			}
  1881  
  1882  			v := getValue(t, tc.value)
  1883  			for _, p := range tc.path {
  1884  				if p == "" {
  1885  					v = v.Template()("label")
  1886  				} else {
  1887  					v = v.Lookup(p)
  1888  				}
  1889  			}
  1890  			b, err := v.MarshalJSON()
  1891  			if err != nil {
  1892  				t.Fatal(err)
  1893  			}
  1894  			if got := string(b); got != tc.want {
  1895  				t.Errorf("\n got: %q\nwant: %q", got, tc.want)
  1896  			}
  1897  		})
  1898  	}
  1899  }
  1900  
  1901  func TestElem(t *testing.T) {
  1902  	testCases := []struct {
  1903  		value string
  1904  		path  []string
  1905  		want  string
  1906  		skip  bool
  1907  	}{{
  1908  		value: `
  1909  		a: [...int]
  1910  		`,
  1911  		path: []string{"a", ""},
  1912  		want: `int`,
  1913  	}, {
  1914  		value: `
  1915  		[Name=string]: { a: Name }
  1916  		`,
  1917  		path: []string{"", "a"},
  1918  		want: `string`,
  1919  	}, {
  1920  		value: `
  1921  		[Name=string]: { a: Name }
  1922  		`,
  1923  		path: []string{""},
  1924  		want: "{\n\ta: string\n}",
  1925  	}, {
  1926  		value: `
  1927  		a: [Foo=string]: [Bar=string]: { b: Foo+Bar }
  1928  		`,
  1929  		path: []string{"a", "", ""},
  1930  		want: "{\n\tb: string + string\n}",
  1931  	}, {
  1932  		value: `
  1933  		a: [Foo=string]: b: [Bar=string]: { c: Foo+Bar }
  1934  		a: foo: b: [Bar=string]: { d: Bar }
  1935  		`,
  1936  		path: []string{"a", "foo", "b", ""},
  1937  		want: "{\n\tc: \"foo\" + string\n\td: string\n}",
  1938  		skip: true, // TODO(p3): Skip because this is just a reordering.
  1939  	}}
  1940  	for _, tc := range testCases {
  1941  		cuetdtest.FullMatrix.Run(t, "", func(t *cuetdtest.M) {
  1942  			if tc.skip {
  1943  				t.TODO_V3()
  1944  			}
  1945  
  1946  			v := getValue(t, tc.value)
  1947  			cue.ValueVertex(v).Finalize(cue.ValueCtx(v)) // TODO: do in instance.
  1948  			for _, p := range tc.path {
  1949  				if p == "" {
  1950  					var ok bool
  1951  					v, ok = v.Elem()
  1952  					if !ok {
  1953  						t.Fatal("expected element")
  1954  					}
  1955  				} else {
  1956  					v = v.Lookup(p)
  1957  				}
  1958  			}
  1959  			got := fmt.Sprint(v)
  1960  			// got := debug.NodeString(v.ctx(), v.v, &debug.Config{Compact: true})
  1961  			if got != tc.want {
  1962  				t.Errorf("\n got: %q\nwant: %q", got, tc.want)
  1963  			}
  1964  		})
  1965  	}
  1966  }
  1967  
  1968  func TestSubsume(t *testing.T) {
  1969  	a := cue.ParsePath("a")
  1970  	b := cue.ParsePath("b")
  1971  	testCases := []struct {
  1972  		value   string
  1973  		pathA   cue.Path
  1974  		pathB   cue.Path
  1975  		options []cue.Option
  1976  		want    bool
  1977  	}{{
  1978  		value: `4`,
  1979  		want:  true,
  1980  	}, {
  1981  		value: `a: string, b: "foo"`,
  1982  		pathA: a,
  1983  		pathB: b,
  1984  		want:  true,
  1985  	}, {
  1986  		value: `a: string, b: "foo"`,
  1987  		pathA: b,
  1988  		pathB: a,
  1989  		want:  false,
  1990  	}, {
  1991  		value: `a: {a: string, b: 4}, b: {a: "foo", b: 4}`,
  1992  		pathA: a,
  1993  		pathB: b,
  1994  		want:  true,
  1995  	}, {
  1996  		value: `a: [string,  4], b: ["foo", 4]`,
  1997  		pathA: a,
  1998  		pathB: b,
  1999  		want:  true,
  2000  	}, {
  2001  		value: `a: [...string], b: ["foo"]`,
  2002  		pathA: a,
  2003  		pathB: b,
  2004  		want:  true,
  2005  	}, {
  2006  		value: `a: [...int], b: ["foo"]`,
  2007  		pathA: a,
  2008  		pathB: b,
  2009  		want:  false,
  2010  	}, {
  2011  		// Issue #566
  2012  		// Closed struct subsuming open struct.
  2013  		value: `
  2014  		#Run: { action: "run", command: [...string] }
  2015  		b: { action: "run", command: ["echo", "hello"] }
  2016  		`,
  2017  		pathA: cue.ParsePath("#Run"),
  2018  		pathB: b,
  2019  
  2020  		// NOTE: this is for v0.2 compatibility. Logically a closed struct
  2021  		// does not subsume an open struct. One could argue that the default
  2022  		// of an open struct is the closed struct with the minimal number
  2023  		// of fields that is an instance of it, though.
  2024  		want: true, // open struct is not subsumed by closed if not final.
  2025  	}, {
  2026  		// Issue #566
  2027  		// Closed struct subsuming open struct.
  2028  		value: `
  2029  			#Run: { action: "run", command: [...string] }
  2030  			b: { action: "run", command: ["echo", "hello"] }
  2031  			`,
  2032  		pathA:   cue.ParsePath("#Run"),
  2033  		pathB:   b,
  2034  		options: []cue.Option{cue.Final()},
  2035  		want:    true,
  2036  	}, {
  2037  		// default
  2038  		value: `
  2039  		a: <5
  2040  		b: *3 | int
  2041  		`,
  2042  		pathA: a,
  2043  		pathB: b,
  2044  		want:  true,
  2045  	}, {
  2046  		// Disable default elimination.
  2047  		value: `
  2048  			a: <5
  2049  			b: *3 | int
  2050  			`,
  2051  		pathA:   a,
  2052  		pathB:   b,
  2053  		options: []cue.Option{cue.Raw()},
  2054  		want:    false,
  2055  	}, {
  2056  		value: `
  2057  			#A: {
  2058  				exact: string
  2059  			} | {
  2060  				regex: string
  2061  			}
  2062  			#B: {
  2063  				exact: string
  2064  			} | {
  2065  				regex: string
  2066  			}
  2067  			`,
  2068  		pathA:   cue.ParsePath("#A"),
  2069  		pathB:   cue.ParsePath("#B"),
  2070  		options: []cue.Option{},
  2071  		want:    true,
  2072  	}, {
  2073  		value: `
  2074  			import "time"
  2075  			a: time.Format(time.ANSIC)
  2076  			b: 1
  2077  			`,
  2078  		pathA: a,
  2079  		pathB: b,
  2080  		want:  false,
  2081  	}}
  2082  	for _, tc := range testCases {
  2083  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
  2084  			v := getValue(t, tc.value)
  2085  			a := v.LookupPath(tc.pathA)
  2086  			b := v.LookupPath(tc.pathB)
  2087  			got := a.Subsume(b, tc.options...) == nil
  2088  			if got != tc.want {
  2089  				t.Errorf("got %v (%v); want %v (%v)", got, a, tc.want, b)
  2090  			}
  2091  		})
  2092  	}
  2093  }
  2094  
  2095  func TestSubsumes(t *testing.T) {
  2096  	a := []string{"a"}
  2097  	b := []string{"b"}
  2098  	testCases := []struct {
  2099  		value string
  2100  		pathA []string
  2101  		pathB []string
  2102  		want  bool
  2103  	}{{
  2104  		value: `4`,
  2105  		want:  true,
  2106  	}, {
  2107  		value: `a: string, b: "foo"`,
  2108  		pathA: a,
  2109  		pathB: b,
  2110  		want:  true,
  2111  	}, {
  2112  		value: `a: string, b: "foo"`,
  2113  		pathA: b,
  2114  		pathB: a,
  2115  		want:  false,
  2116  	}, {
  2117  		value: `a: {a: string, b: 4}, b: {a: "foo", b: 4}`,
  2118  		pathA: a,
  2119  		pathB: b,
  2120  		want:  true,
  2121  	}, {
  2122  		value: `a: [string,  4], b: ["foo", 4]`,
  2123  		pathA: a,
  2124  		pathB: b,
  2125  		want:  true,
  2126  	}, {
  2127  		value: `a: [...string], b: ["foo"]`,
  2128  		pathA: a,
  2129  		pathB: b,
  2130  		want:  true,
  2131  	}, {
  2132  		value: `a: [...int], b: ["foo"]`,
  2133  		pathA: a,
  2134  		pathB: b,
  2135  		want:  false,
  2136  	}, {
  2137  		value: `
  2138  		a: { action: "run", command: [...string] }
  2139  		b: { action: "run", command: ["echo", "hello"] }
  2140  		`,
  2141  		pathA: a,
  2142  		pathB: b,
  2143  		want:  true,
  2144  	}}
  2145  	for _, tc := range testCases {
  2146  		cuetdtest.FullMatrix.Run(t, tc.value, func(t *cuetdtest.M) {
  2147  			v := getValue(t, tc.value)
  2148  			a := v.Lookup(tc.pathA...)
  2149  			b := v.Lookup(tc.pathB...)
  2150  			got := a.Subsumes(b)
  2151  			if got != tc.want {
  2152  				t.Errorf("got %v (%v); want %v (%v)", got, a, tc.want, b)
  2153  			}
  2154  		})
  2155  	}
  2156  }
  2157  
  2158  func TestUnify(t *testing.T) {
  2159  	a := "a"
  2160  	b := "b"
  2161  	type testCase struct {
  2162  		value string
  2163  		pathA string
  2164  		pathB string
  2165  		want  string
  2166  	}
  2167  	testCases := []testCase{{
  2168  		value: `4`,
  2169  		want:  `4`,
  2170  	}, {
  2171  		value: `a: string, b: "foo"`,
  2172  		pathA: a,
  2173  		pathB: b,
  2174  		want:  `"foo"`,
  2175  	}, {
  2176  		value: `a: string, b: "foo"`,
  2177  		pathA: b,
  2178  		pathB: a,
  2179  		want:  `"foo"`,
  2180  	}, {
  2181  		value: `a: {a: string, b: 4}, b: {a: "foo", b: 4}`,
  2182  		pathA: a,
  2183  		pathB: b,
  2184  		want:  `{"a":"foo","b":4}`,
  2185  	}, {
  2186  		value: `a: [string,  4], b: ["foo", 4]`,
  2187  		pathA: a,
  2188  		pathB: b,
  2189  		want:  `["foo",4]`,
  2190  	}, {
  2191  		value: `a: {a: string, _hidden: int, _#hidden: int}, b: close({a: "foo"})`,
  2192  		pathA: a,
  2193  		pathB: b,
  2194  		want:  `{"a":"foo"}`,
  2195  	}, {
  2196  		// Issue #2325: let should not result in a closedness error.
  2197  		value: `#T: {
  2198  			...
  2199  		}
  2200  		b: {
  2201  			let foobar = {}
  2202  			 _fb: foobar
  2203  		}`,
  2204  		pathA: "#T",
  2205  		pathB: b,
  2206  		want:  `{}`,
  2207  	}, {
  2208  		value: `
  2209  		a: #A: "foo"
  2210  		#B: {...}
  2211  		`,
  2212  		pathA: a,
  2213  		pathB: "#B",
  2214  		want:  `{}`,
  2215  	}}
  2216  	// TODO(tdtest): use cuetest.Run when supported.
  2217  	cuetdtest.FullMatrix.Do(t, func(m *cuetdtest.M) {
  2218  		tdtest.Run(t, testCases, func(t *cuetest.T, tc *testCase) {
  2219  			v := getValue(m, tc.value)
  2220  			x := v.LookupPath(cue.ParsePath(tc.pathA))
  2221  			y := v.LookupPath(cue.ParsePath(tc.pathB))
  2222  			b, err := x.Unify(y).MarshalJSON()
  2223  			if err != nil {
  2224  				t.Fatal(err)
  2225  			}
  2226  			t.Equal(string(b), tc.want)
  2227  		})
  2228  	})
  2229  }
  2230  
  2231  func TestUnifyAccept(t *testing.T) {
  2232  	type testCase struct {
  2233  		value string
  2234  		want  string
  2235  	}
  2236  	testCases := []testCase{{
  2237  		value: `#v: 4, #w: 4, #accept: int`,
  2238  		want:  `4`,
  2239  	}, {
  2240  		value: `#v: string, #w: "foo", #accept: string`,
  2241  		want:  `"foo"`,
  2242  	}, {
  2243  		value: `#v: {a: "foo"}, #w: {b: 4}, #accept: {a: string, b: int}`,
  2244  		want:  `{"a":"foo","b":4}`,
  2245  	}, {
  2246  		value: `#v: [string,  4], #w: ["foo", 4], #accept: [string, int, ...]`,
  2247  		want:  `["foo",4]`,
  2248  	}, {
  2249  		value: `#v: {a: string, b: 1, _#hidden: int}, #w: {a: "foo"}, #accept: {...}`,
  2250  		want:  `{"a":"foo","b":1}`,
  2251  	}, {
  2252  		// Issue #2325: let should not result in a closedness error.
  2253  		value: `#accept: {
  2254  			...
  2255  		}
  2256  		#v: {}
  2257  		#w: {
  2258  			let foobar = {}
  2259  			 _fb: foobar
  2260  		}`,
  2261  		want: `{}`,
  2262  	}, {
  2263  		value: `
  2264  		#v: #v: "foo"
  2265  		#w: {b:1}
  2266  		#accept: {...}
  2267  		`,
  2268  		want: `{"b":1}`,
  2269  	}}
  2270  	// TODO(tdtest): use cuetest.Run when supported.
  2271  	cuetdtest.FullMatrix.Do(t, func(m *cuetdtest.M) {
  2272  		tdtest.Run(t, testCases, func(t *cuetest.T, tc *testCase) {
  2273  			v := getValue(m, tc.value)
  2274  			x := v.LookupPath(cue.ParsePath("#v"))
  2275  			y := v.LookupPath(cue.ParsePath("#w"))
  2276  			a := v.LookupPath(cue.ParsePath("#accept"))
  2277  			b, err := x.UnifyAccept(y, a).MarshalJSON()
  2278  			if err != nil {
  2279  				t.Fatal(err)
  2280  			}
  2281  			t.Equal(string(b), tc.want)
  2282  		})
  2283  	})
  2284  }
  2285  
  2286  func TestEquals(t *testing.T) {
  2287  	testCases := []struct {
  2288  		a, b string
  2289  		want bool
  2290  	}{{
  2291  		`4`, `4`, true,
  2292  	}, {
  2293  		`"str"`, `2`, false,
  2294  	}, {
  2295  		`2`, `3`, false,
  2296  	}, {
  2297  		`[1]`, `[3]`, false,
  2298  	}, {
  2299  		`[{a: 1,...}]`, `[{a: 1,...}]`, true,
  2300  	}, {
  2301  		`[]`, `[]`, true,
  2302  	}, {
  2303  		`{
  2304  			a: b,
  2305  			b: a,
  2306  		}`,
  2307  		`{
  2308  			a: b,
  2309  			b: a,
  2310  		}`,
  2311  		true,
  2312  	}, {
  2313  		`{
  2314  			a: "foo",
  2315  			b: "bar",
  2316  		}`,
  2317  		`{
  2318  			a: "foo",
  2319  		}`,
  2320  		false,
  2321  	}, {
  2322  		// Ignore closedness
  2323  		`{ #Foo: { k: 1 }, a: #Foo }`,
  2324  		`{ #Foo: { k: 1 }, a: { k: 1 } }`,
  2325  		true,
  2326  	}, {
  2327  		// Ignore optional fields
  2328  		`{ #Foo: { k: 1 }, a: #Foo }`,
  2329  		`{ #Foo: { k: 1 }, a: { #Foo, i?: 1 } }`,
  2330  		true,
  2331  	}, {
  2332  		// Treat embedding as equal
  2333  		`{ a: 2, b: { 3 } }`,
  2334  		`{ a: { 2 }, b: 3 }`,
  2335  		true,
  2336  	}}
  2337  	for _, tc := range testCases {
  2338  		cuetdtest.FullMatrix.Run(t, "", func(t *cuetdtest.M) {
  2339  			ctx := t.Context()
  2340  
  2341  			a := mustCompile(t, ctx, tc.a)
  2342  			b := mustCompile(t, ctx, tc.b)
  2343  			got := a.Equals(b)
  2344  			if got != tc.want {
  2345  				t.Errorf("got %v; want %v", got, tc.want)
  2346  			}
  2347  		})
  2348  	}
  2349  }
  2350  
  2351  // TODO: options: disallow cycles.
  2352  func TestValidate(t *testing.T) {
  2353  	testCases := []struct {
  2354  		desc string
  2355  		in   string
  2356  		err  bool
  2357  		opts []cue.Option
  2358  
  2359  		skip bool
  2360  	}{{
  2361  		desc: "issue #51",
  2362  		in: `
  2363  		a: [string]: foo
  2364  		a: b: {}
  2365  		`,
  2366  		err: true,
  2367  	}, {
  2368  		desc: "concrete",
  2369  		in: `
  2370  		a: 1
  2371  		b: { c: 2, d: 3 }
  2372  		c: d: e: f: 5
  2373  		g?: int
  2374  		`,
  2375  		opts: []cue.Option{cue.Concrete(true)},
  2376  	}, {
  2377  		desc: "definition error",
  2378  		in: `
  2379  			#b: 1 & 2
  2380  			`,
  2381  		opts: []cue.Option{},
  2382  		err:  true,
  2383  	}, {
  2384  		desc: "definition error okay if optional",
  2385  		in: `
  2386  			#b?: 1 & 2
  2387  			`,
  2388  		opts: []cue.Option{},
  2389  	}, {
  2390  		desc: "definition with optional",
  2391  		in: `
  2392  			#b: {
  2393  				a: int
  2394  				b?: >=0
  2395  			}
  2396  		`,
  2397  		opts: []cue.Option{cue.Concrete(true)},
  2398  	}, {
  2399  		desc: "disjunction",
  2400  		in:   `a: 1 | 2`,
  2401  	}, {
  2402  		desc: "disjunction concrete",
  2403  		in:   `a: 1 | 2`,
  2404  		opts: []cue.Option{cue.Concrete(true)},
  2405  		err:  true,
  2406  	}, {
  2407  		desc: "incomplete concrete",
  2408  		in:   `a: string`,
  2409  	}, {
  2410  		desc: "incomplete",
  2411  		in:   `a: string`,
  2412  		opts: []cue.Option{cue.Concrete(true)},
  2413  		err:  true,
  2414  	}, {
  2415  		desc: "list",
  2416  		in:   `a: [{b: string}, 3]`,
  2417  	}, {
  2418  		desc: "list concrete",
  2419  		in:   `a: [{b: string}, 3]`,
  2420  		opts: []cue.Option{cue.Concrete(true)},
  2421  		err:  true,
  2422  	}, {
  2423  		desc: "allow cycles",
  2424  		in: `
  2425  			a: b - 100
  2426  			b: a + 100
  2427  			c: [c[1], c[0]]
  2428  			`,
  2429  	}, {
  2430  		desc: "disallow cycles",
  2431  		in: `
  2432  			a: b - 100
  2433  			b: a + 100
  2434  			c: [c[1], c[0]]
  2435  			`,
  2436  		opts: []cue.Option{cue.DisallowCycles(true)},
  2437  		err:  true,
  2438  
  2439  		// TODO: in the new evaluator these are not considered to be cycles
  2440  		// but rather incomplete errors. This is actually the correct behavior
  2441  		// and the old evaluator treats errors like this by default.
  2442  		// The option tested in this test was added for backwards compatibility
  2443  		// when the old evaluator was made to treat these kinds of errors
  2444  		// equally. With the new evaluator we can no longer distinguish these
  2445  		// errors. For now, at least. Consider what to do with this option.
  2446  		skip: true,
  2447  	}, {
  2448  		desc: "builtins are okay",
  2449  		in: `
  2450  		import "time"
  2451  
  2452  		a: { b: time.Duration } | { c: time.Duration }
  2453  		`,
  2454  	}, {
  2455  		desc: "comprehension error",
  2456  		in: `
  2457  			a: { if b == "foo" { field: 2 } }
  2458  			`,
  2459  		err: true,
  2460  	}, {
  2461  		desc: "ignore optional in schema",
  2462  		in: `
  2463  		#Schema1: {
  2464  			a?: int
  2465  		}
  2466  		instance1: #Schema1
  2467  		`,
  2468  		opts: []cue.Option{cue.Concrete(true)},
  2469  	}, {
  2470  		desc: "issue324",
  2471  		in: `
  2472  		import "encoding/yaml"
  2473  
  2474  		x: string
  2475  		a: b: c: *["\(x)"] | _
  2476  		d: yaml.Marshal(a.b)
  2477  		`,
  2478  	}, {
  2479  		desc: "allow non-concrete values for definitions",
  2480  		in: `
  2481  		variables: #variables
  2482  
  2483  		{[!~"^[.]"]: #job}
  2484  
  2485  		#variables: [string]: int | string
  2486  
  2487  		#job: ({a: int} | {b: int}) & {
  2488  			"variables"?: #variables
  2489  		}
  2490  		`,
  2491  	}}
  2492  	for _, tc := range testCases {
  2493  		cuetdtest.FullMatrix.Run(t, tc.desc, func(t *cuetdtest.M) {
  2494  			if tc.skip {
  2495  				t.TODO_V3()
  2496  			}
  2497  
  2498  			ctx := t.Context()
  2499  			val := ctx.CompileString(tc.in, cue.Filename("validate"))
  2500  			err := val.Validate(tc.opts...)
  2501  			if gotErr := err != nil; gotErr != tc.err {
  2502  				t.Errorf("got %v; want %v", err, tc.err)
  2503  			}
  2504  		})
  2505  	}
  2506  }
  2507  
  2508  func TestPath(t *testing.T) {
  2509  	config := `
  2510  	a: b: c: 5
  2511  	b: {
  2512  		b1: 3
  2513  		b2: 4
  2514  		"b 3": 5
  2515  		"4b": 6
  2516  		l: [
  2517  			{a: 2},
  2518  			{c: 2},
  2519  		]
  2520  	}
  2521  	`
  2522  	mkpath := func(p ...string) []string { return p }
  2523  	testCases := [][]string{
  2524  		mkpath("a", "b", "c"),
  2525  		mkpath("b", "l", "1", "c"),
  2526  		mkpath("b", `"b 3"`),
  2527  		mkpath("b", `"4b"`),
  2528  	}
  2529  	for _, tc := range testCases {
  2530  		cuetdtest.FullMatrix.Run(t, strings.Join(tc, "."), func(t *cuetdtest.M) {
  2531  			ctx := t.Context()
  2532  			val := mustCompile(t, ctx, config)
  2533  
  2534  			v := val.Lookup(tc[0])
  2535  			for _, e := range tc[1:] {
  2536  				if '0' <= e[0] && e[0] <= '9' {
  2537  					i, err := strconv.Atoi(e)
  2538  					if err != nil {
  2539  						t.Fatal(err)
  2540  					}
  2541  					iter, err := v.List()
  2542  					if err != nil {
  2543  						t.Fatal(err)
  2544  					}
  2545  					for c := 0; iter.Next(); c++ {
  2546  						if c == i {
  2547  							v = iter.Value()
  2548  							break
  2549  						}
  2550  					}
  2551  				} else if e[0] == '"' {
  2552  					v = v.Lookup(e[1 : len(e)-1])
  2553  				} else {
  2554  					v = v.Lookup(e)
  2555  				}
  2556  			}
  2557  			got := cue.PathToStrings(v.Path())
  2558  			if !reflect.DeepEqual(got, tc) {
  2559  				t.Errorf("got %v; want %v", got, tc)
  2560  			}
  2561  		})
  2562  	}
  2563  }
  2564  
  2565  func TestValueLookup(t *testing.T) {
  2566  	config := `
  2567  		a: {
  2568  			a: 0
  2569  			b: 1
  2570  			c: 2
  2571  		}
  2572  		b: {
  2573  			d: a.a
  2574  			e: int
  2575  		}
  2576  	`
  2577  
  2578  	strList := func(s ...string) []string { return s }
  2579  
  2580  	testCases := []struct {
  2581  		config    string
  2582  		path      []string
  2583  		str       string
  2584  		notExists bool
  2585  	}{{
  2586  		config: "_|_",
  2587  		path:   strList(""),
  2588  		str:    "explicit error (_|_ literal) in source",
  2589  	}, {
  2590  		config: "_|_",
  2591  		path:   strList("a"),
  2592  		str:    "explicit error (_|_ literal) in source",
  2593  	}, {
  2594  		config: config,
  2595  		path:   strList(),
  2596  		str:    "{a:{a:0,b:1,c:2},b:{d:0,e:int}",
  2597  	}, {
  2598  		config: config,
  2599  		path:   strList("a", "a"),
  2600  		str:    "0",
  2601  	}, {
  2602  		config: config,
  2603  		path:   strList("a"),
  2604  		str:    "{a:0,b:1,c:2}",
  2605  	}, {
  2606  		config: config,
  2607  		path:   strList("b", "d"),
  2608  		str:    "0",
  2609  	}, {
  2610  		config:    config,
  2611  		path:      strList("c", "non-existing"),
  2612  		str:       "not found",
  2613  		notExists: true,
  2614  	}, {
  2615  		config: config,
  2616  		path:   strList("b", "d", "lookup in non-struct"),
  2617  		str:    "cannot use value 0 (type int) as struct",
  2618  	}}
  2619  	for _, tc := range testCases {
  2620  		cuetdtest.FullMatrix.Run(t, tc.str, func(t *cuetdtest.M) {
  2621  			v := getValue(t, tc.config).Lookup(tc.path...)
  2622  			if got := !v.Exists(); got != tc.notExists {
  2623  				t.Errorf("exists: got %v; want %v", got, tc.notExists)
  2624  			}
  2625  
  2626  			got := cue.ValueCtx(v).Str(cue.ValueVertex(v))
  2627  			if tc.str == "" {
  2628  				t.Fatalf("str empty, got %q", got)
  2629  			}
  2630  			if !strings.Contains(got, tc.str) {
  2631  				t.Errorf("\n got %v\nwant %v", got, tc.str)
  2632  			}
  2633  		})
  2634  	}
  2635  }
  2636  
  2637  func cmpError(a, b error) bool {
  2638  	if a == nil {
  2639  		return b == nil
  2640  	}
  2641  	if b == nil {
  2642  		return a == nil
  2643  	}
  2644  	return a.Error() == b.Error()
  2645  }
  2646  
  2647  // TODO: duplicate docs.
  2648  func TestValueDoc(t *testing.T) {
  2649  	const config = `
  2650  	// foobar defines at least foo.
  2651  	package foobar
  2652  
  2653  	// A Foo fooses stuff.
  2654  	Foo: {
  2655  		// field1 is an int.
  2656  		field1: int
  2657  
  2658  		field2: int
  2659  
  2660  		// duplicate field comment
  2661  		dup3: int
  2662  	}
  2663  
  2664  	// foos are instances of Foo.
  2665  	foos: [string]: Foo
  2666  
  2667  	// My first little foo.
  2668  	foos: MyFoo: {
  2669  		// local field comment.
  2670  		field1: 0
  2671  
  2672  		// Dangling comment.
  2673  
  2674  		// other field comment.
  2675  		field2: 1
  2676  
  2677  		// duplicate field comment
  2678  		dup3: int
  2679  	}
  2680  
  2681  	bar: {
  2682  		// comment from bar on field 1
  2683  		field1: int
  2684  		// comment from bar on field 2
  2685  		field2: int // don't include this
  2686  	}
  2687  
  2688  	baz: bar & {
  2689  		// comment from baz on field 1
  2690  		field1: int
  2691  		field2: int
  2692  	}
  2693  	`
  2694  	config2 := `
  2695  	// Another Foo.
  2696  	Foo: {}
  2697  	`
  2698  
  2699  	cuetdtest.FullMatrix.Do(t, func(t *cuetdtest.M) {
  2700  		ctx := t.Context()
  2701  		v1 := mustCompile(t, ctx, config)
  2702  		v2 := mustCompile(t, ctx, config2)
  2703  		both := v1.Unify(v2)
  2704  
  2705  		testCases := []struct {
  2706  			val  cue.Value
  2707  			path string
  2708  			doc  string
  2709  			skip bool
  2710  		}{{
  2711  			val:  v1,
  2712  			path: "foos",
  2713  			doc:  "foos are instances of Foo.\n",
  2714  		}, {
  2715  			val:  v1,
  2716  			path: "foos MyFoo",
  2717  			doc:  "My first little foo.\n",
  2718  		}, {
  2719  			val:  v1,
  2720  			path: "foos MyFoo field1",
  2721  			doc: `local field comment.
  2722  
  2723  field1 is an int.
  2724  `,
  2725  		}, {
  2726  			val:  v1,
  2727  			path: "foos MyFoo field2",
  2728  			doc:  "other field comment.\n",
  2729  		}, {
  2730  			// Duplicates are now removed.
  2731  			val:  v1,
  2732  			path: "foos MyFoo dup3",
  2733  			doc:  "duplicate field comment\n",
  2734  		}, {
  2735  			val:  v1,
  2736  			path: "bar field1",
  2737  			doc:  "comment from bar on field 1\n",
  2738  		}, {
  2739  			val:  v1,
  2740  			path: "baz field1",
  2741  			doc: `comment from bar on field 1
  2742  
  2743  comment from baz on field 1
  2744  `,
  2745  			// New evaluaotor orders the comments differently (arguably better).
  2746  			skip: true,
  2747  		}, {
  2748  			val:  v1,
  2749  			path: "baz field2",
  2750  			doc:  "comment from bar on field 2\n",
  2751  		}, {
  2752  			val:  v2,
  2753  			path: "Foo",
  2754  			doc: `Another Foo.
  2755  `,
  2756  		}, {
  2757  			val:  both,
  2758  			path: "Foo",
  2759  			doc: `A Foo fooses stuff.
  2760  
  2761  Another Foo.
  2762  `,
  2763  		}}
  2764  		for _, tc := range testCases {
  2765  			if tc.skip {
  2766  				t.TODO_V3()
  2767  			}
  2768  			t.Run("field:"+tc.path, func(t *testing.T) {
  2769  				v := tc.val.Lookup(strings.Split(tc.path, " ")...)
  2770  				doc := docStr(v.Doc())
  2771  				if doc != tc.doc {
  2772  					t.Errorf("doc: got:\n%vwant:\n%v", doc, tc.doc)
  2773  				}
  2774  			})
  2775  		}
  2776  		want := "foobar defines at least foo.\n"
  2777  		if got := docStr(v1.Doc()); got != want {
  2778  			t.Errorf("pkg: got:\n%vwant:\n%v", got, want)
  2779  		}
  2780  	})
  2781  }
  2782  
  2783  func docStr(docs []*ast.CommentGroup) string {
  2784  	doc := ""
  2785  	for _, d := range docs {
  2786  		if doc != "" {
  2787  			doc += "\n"
  2788  		}
  2789  		doc += d.Text()
  2790  	}
  2791  	return doc
  2792  }
  2793  
  2794  // TODO: unwrap marshal error
  2795  // TODO: improve error messages
  2796  func TestMarshalJSON(t *testing.T) {
  2797  	type testCase struct {
  2798  		value string
  2799  		json  string
  2800  		err   string
  2801  	}
  2802  	testCases := []testCase{{
  2803  		value: `""`,
  2804  		json:  `""`,
  2805  	}, {
  2806  		value: `null`,
  2807  		json:  `null`,
  2808  	}, {
  2809  		value: `_|_`,
  2810  		err:   "explicit error (_|_ literal) in source",
  2811  	}, {
  2812  		value: `(a.b)
  2813  		a: {}`,
  2814  		err: "undefined field",
  2815  	}, {
  2816  		value: `true`,
  2817  		json:  `true`,
  2818  	}, {
  2819  		value: `false`,
  2820  		json:  `false`,
  2821  	}, {
  2822  		value: `bool`,
  2823  		err:   "cannot convert incomplete value",
  2824  	}, {
  2825  		value: `"str"`,
  2826  		json:  `"str"`,
  2827  	}, {
  2828  		value: `12_000`,
  2829  		json:  `12000`,
  2830  	}, {
  2831  		value: `12.000`,
  2832  		json:  `12.000`,
  2833  	}, {
  2834  		value: `12M`,
  2835  		json:  `12000000`,
  2836  	}, {
  2837  		value: `3.0e100`,
  2838  		json:  `3.0E+100`,
  2839  	}, {
  2840  		value: `0/0`,
  2841  		err:   "division undefined",
  2842  	}, {
  2843  		value: `[]`,
  2844  		json:  `[]`,
  2845  	}, {
  2846  		value: `[1, 2, 3]`,
  2847  		json:  `[1,2,3]`,
  2848  	}, {
  2849  		value: `[int]`,
  2850  		err:   `0: cannot convert incomplete value`,
  2851  	}, {
  2852  		value: `{}`,
  2853  		json:  `{}`,
  2854  	}, {
  2855  		value: `{a: 2, b: 3, c: ["A", "B"]}`,
  2856  		json:  `{"a":2,"b":3,"c":["A","B"]}`,
  2857  	}, {
  2858  		value: `{a: 2, b: 3, c: [string, "B"]}`,
  2859  		err:   `c.0: cannot convert incomplete value`,
  2860  	}, {
  2861  		value: `{a: [{b: [0, {c: string}] }] }`,
  2862  		err:   `a.0.b.1.c: cannot convert incomplete value`,
  2863  	}, {
  2864  		value: `{foo?: 1, bar?: 2, baz: 3}`,
  2865  		json:  `{"baz":3}`,
  2866  	}, {
  2867  		value: `{foo!: 1, bar: 2}`,
  2868  		err:   "cue: marshal error: foo: field is required but not present",
  2869  	}, {
  2870  		// Has an unresolved cycle, but should not matter as all fields involved
  2871  		// are optional
  2872  		value: `{foo?: bar, bar?: foo, baz: 3}`,
  2873  		json:  `{"baz":3}`,
  2874  	}, {
  2875  		// Issue #107
  2876  		value: `a: 1.0/1`,
  2877  		json:  `{"a":1.0}`,
  2878  	}, {
  2879  		// Issue #108
  2880  		value: `
  2881  		a: int
  2882  		a: >0
  2883  		a: <2
  2884  
  2885  		b: int
  2886  		b: >=0.9
  2887  		b: <1.1
  2888  
  2889  		c: int
  2890  		c: >1
  2891  		c: <=2
  2892  
  2893  		d: int
  2894  		d: >=1
  2895  		d: <=1.5
  2896  
  2897  		e: int
  2898  		e: >=1
  2899  		e: <=1.32
  2900  
  2901  		f: >=1.1 & <=1.1
  2902  		`,
  2903  		json: `{"a":1,"b":1,"c":2,"d":1,"e":1,"f":1.1}`,
  2904  	}, {
  2905  		value: `
  2906  		#Task: {
  2907  			{
  2908  				op:          "pull"
  2909  				tag:         *"latest" | string
  2910  				tagInString: tag + "dd"
  2911  			} | {
  2912  				op: "scratch"
  2913  			}
  2914  		}
  2915  
  2916  		foo: #Task & {"op": "pull"}
  2917  		`,
  2918  		json: `{"foo":{"op":"pull","tag":"latest","tagInString":"latestdd"}}`,
  2919  	}, {
  2920  		// Issue #326
  2921  		value: `x: "\(string)": "v"`,
  2922  		err:   `x: invalid interpolation`,
  2923  	}, {
  2924  		// Issue #326
  2925  		value: `x: "\(bool)": "v"`,
  2926  		err:   `invalid interpolation`,
  2927  	}, {
  2928  		// Issue #326
  2929  		value: `
  2930  		x: {
  2931  			for k, v in y {
  2932  				"\(k)": v
  2933  			}
  2934  		}
  2935  		y: {}
  2936  		`,
  2937  		json: `{"x":{},"y":{}}`,
  2938  	}, {
  2939  		// Issue #326
  2940  		value: `
  2941  		x: {
  2942  			for k, v in y {
  2943  				"\(k)": v
  2944  			}
  2945  		}
  2946  		y: _
  2947  		`,
  2948  		err: `x: cannot range over y (incomplete type _)`,
  2949  	}, {
  2950  		value: `
  2951  		package foo
  2952  
  2953  		#SomeBaseType: {
  2954  			"a" | "b"
  2955  			#AUTO: "z"
  2956  		}
  2957  
  2958  		V1: ("x" | "y") | *"z"
  2959  		V2: ("x" | "y") | *#SomeBaseType.#AUTO
  2960  		`,
  2961  		err: "cue: marshal error: V2: cannot convert incomplete value \"|((string){ \\\"x\\\" }, (string){ \\\"y\\\" })\" to JSON",
  2962  	}}
  2963  	for i, tc := range testCases {
  2964  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%d/%v", i, tc.value), func(t *cuetdtest.M) {
  2965  			t.TODO_V3()
  2966  
  2967  			val := getValue(t, tc.value)
  2968  			b, err := val.MarshalJSON()
  2969  			checkFatal(t.T, err, tc.err, "init")
  2970  
  2971  			if got := string(b); got != tc.json {
  2972  				t.Errorf("\n got %v;\nwant %v", got, tc.json)
  2973  			}
  2974  		})
  2975  	}
  2976  }
  2977  
  2978  func TestWalk(t *testing.T) {
  2979  	testCases := []struct {
  2980  		value string
  2981  		out   string
  2982  	}{{
  2983  		value: `""`,
  2984  		out:   `""`,
  2985  	}, {
  2986  		value: `null`,
  2987  		out:   `null`,
  2988  	}, {
  2989  		value: `_|_`,
  2990  		out:   "_|_(explicit error (_|_ literal) in source)",
  2991  	}, {
  2992  		value: `(a.b)
  2993  			a: {}`,
  2994  		out: `_|_(undefined field: b)`,
  2995  	}, {
  2996  		value: `true`,
  2997  		out:   `true`,
  2998  	}, {
  2999  		value: `false`,
  3000  		out:   `false`,
  3001  	}, {
  3002  		value: `bool`,
  3003  		out:   "bool",
  3004  	}, {
  3005  		value: `"str"`,
  3006  		out:   `"str"`,
  3007  	}, {
  3008  		value: `12_000`,
  3009  		out:   `12000`,
  3010  		// out:   `12_000`,
  3011  	}, {
  3012  		value: `12.000`,
  3013  		out:   `12.000`,
  3014  	}, {
  3015  		value: `12M`,
  3016  		out:   `12000000`,
  3017  		// out:   `12M`,
  3018  	}, {
  3019  		value: `3.0e100`,
  3020  		out:   `3.0e+100`,
  3021  		// out:   `3.0e100`,
  3022  	}, {
  3023  		value: `[]`,
  3024  		out:   `[]`,
  3025  	}, {
  3026  		value: `[1, 2, 3]`,
  3027  		out:   `[1,2,3]`,
  3028  	}, {
  3029  		value: `[int]`,
  3030  		out:   `[int]`,
  3031  	}, {
  3032  		value: `3 * [1, 2]`,
  3033  		out:   `[1,2,1,2,1,2]`,
  3034  	}, {
  3035  		value: `{}`,
  3036  		out:   `{}`,
  3037  	}, {
  3038  		value: `{a: 2, b: 3, c: ["A", "B"]}`,
  3039  		out:   `{a:2,b:3,c:["A","B"]}`,
  3040  	}}
  3041  	for i, tc := range testCases {
  3042  		cuetdtest.FullMatrix.Run(t, fmt.Sprintf("%d/%v", i, tc.value), func(t *cuetdtest.M) {
  3043  			t.TODO_V3()
  3044  
  3045  			val := getValue(t, tc.value)
  3046  			buf := []byte{}
  3047  			stripComma := func() {
  3048  				if n := len(buf) - 1; buf[n] == ',' {
  3049  					buf = buf[:n]
  3050  				}
  3051  			}
  3052  			val.Walk(func(v cue.Value) bool {
  3053  				v = v.Eval()
  3054  				if !cue.ValueVertex(v).Label.IsInt() {
  3055  					if k, ok := v.Label(); ok {
  3056  						buf = append(buf, k+":"...)
  3057  					}
  3058  				}
  3059  				switch v.Kind() {
  3060  				case cue.StructKind:
  3061  					buf = append(buf, '{')
  3062  				case cue.ListKind:
  3063  					buf = append(buf, '[')
  3064  				default:
  3065  					if b := cue.ValueVertex(v).Bottom(); b != nil {
  3066  						s := cue.DebugStr(cue.ValueCtx(v), b)
  3067  						buf = append(buf, fmt.Sprint(s, ",")...)
  3068  						return true
  3069  					}
  3070  					buf = append(buf, fmt.Sprint(v, ",")...)
  3071  				}
  3072  				return true
  3073  			}, func(v cue.Value) {
  3074  				switch v.Kind() {
  3075  				case cue.StructKind:
  3076  					stripComma()
  3077  					buf = append(buf, "},"...)
  3078  				case cue.ListKind:
  3079  					stripComma()
  3080  					buf = append(buf, "],"...)
  3081  				}
  3082  			})
  3083  			stripComma()
  3084  			if got := string(buf); got != tc.out {
  3085  				t.Errorf("\n got %v;\nwant %v", got, tc.out)
  3086  			}
  3087  		})
  3088  	}
  3089  }
  3090  
  3091  func TestReferencePath(t *testing.T) {
  3092  	testCases := []struct {
  3093  		input          string
  3094  		want           string
  3095  		wantImportPath string
  3096  		alt            string
  3097  	}{{
  3098  		input: "v: w: x: _|_",
  3099  		want:  "",
  3100  	}, {
  3101  		input: "v: w: x: 2",
  3102  		want:  "",
  3103  	}, {
  3104  		input: "v: w: x: a, a: 1",
  3105  		want:  "a",
  3106  	}, {
  3107  		input: "v: w: x: a.b.c, a: b: c: 1",
  3108  		want:  "a.b.c",
  3109  	}, {
  3110  		input: "if true { v: w: x: a, a: 1 }",
  3111  		want:  "a",
  3112  	}, {
  3113  		input: "v: w: x: w.a.b.c, v: w: a: b: c: 1",
  3114  		want:  "v.w.a.b.c",
  3115  	}, {
  3116  		input: `v: w: x: w.a.b.c, v: w: a: b: c: 1, #D: 3, opt?: 3, "v\(#D)": 3, X: {a: 3}, X`,
  3117  		want:  "v.w.a.b.c",
  3118  	}, {
  3119  		input: `
  3120  		v: w: x: w.a[bb]["c"]
  3121  		v: w: a: b: c: 1
  3122  		bb: "b"`,
  3123  		want: "v.w.a.b.c",
  3124  	}, {
  3125  		input: `
  3126  		X="\(y)": 1
  3127  		v: w: x: X // TODO: Move up for crash
  3128  		y: "foo"`,
  3129  		want: "foo",
  3130  	}, {
  3131  		input: `
  3132  		v: w: _
  3133  		v: [X=string]: x: a[X]
  3134  		a: w: 1`,
  3135  		want: "a.w",
  3136  	}, {
  3137  		input: `v: {
  3138  			for t in src {
  3139  				w: "t\(t)": 1
  3140  				w: "\(t)": w["t\(t)"]
  3141  			}
  3142  		},
  3143  		src: ["x", "y"]`,
  3144  		want: "v.w.tx",
  3145  	}, {
  3146  		input: `
  3147  		v: w: x: a
  3148  		a: 1
  3149  		for i in [] {
  3150  		}
  3151  		`,
  3152  		want: "a",
  3153  	}, {
  3154  		input: `
  3155  		v: w: close({x: a})
  3156  		a: 1
  3157  		`,
  3158  		want: "a",
  3159  	}, {
  3160  		input: `
  3161  		import "math"
  3162  
  3163  		v: w: x: math.Pi
  3164  		`,
  3165  		want:           "Pi",
  3166  		wantImportPath: "math",
  3167  		alt:            "3.14159265358979323846264338327950288419716939937510582097494459",
  3168  	}}
  3169  	for _, tc := range testCases {
  3170  		cuetdtest.FullMatrix.Run(t, "", func(t *cuetdtest.M) {
  3171  			ctx := t.Context()
  3172  
  3173  			val := ctx.CompileString(tc.input, cue.Filename("in"))
  3174  			v := val.Lookup("v", "w", "x")
  3175  
  3176  			root, path := v.ReferencePath()
  3177  			if got := path.String(); got != tc.want {
  3178  				t.Errorf("\n got %v;\nwant %v", got, tc.want)
  3179  			}
  3180  			if tc.want != "" {
  3181  				want := "1"
  3182  				if tc.alt != "" {
  3183  					want = tc.alt
  3184  				}
  3185  				v := fmt.Sprint(root.LookupPath(path))
  3186  				if v != want {
  3187  					t.Errorf("path resolved to %s; want %s", v, want)
  3188  				}
  3189  				buildInst := root.BuildInstance()
  3190  				if buildInst == nil {
  3191  					t.Fatalf("no build instance found for reference path root")
  3192  				}
  3193  				if got, want := buildInst.ImportPath, tc.wantImportPath; got != want {
  3194  					t.Errorf("unexpected import path; got %q want %q", got, want)
  3195  				}
  3196  			}
  3197  
  3198  			inst, a := v.Reference()
  3199  			if got := strings.Join(a, "."); got != tc.want {
  3200  				t.Errorf("\n got %v;\nwant %v", got, tc.want)
  3201  			}
  3202  
  3203  			if tc.want != "" {
  3204  				want := "1"
  3205  				if tc.alt != "" {
  3206  					want = tc.alt
  3207  				}
  3208  				v := fmt.Sprint(inst.Lookup(a...))
  3209  				if v != want {
  3210  					t.Errorf("path resolved to %s; want %s", v, want)
  3211  				}
  3212  			}
  3213  		})
  3214  	}
  3215  }
  3216  
  3217  func TestZeroValueBuildInstance(t *testing.T) {
  3218  	inst := cue.Value{}.BuildInstance()
  3219  	if inst != nil {
  3220  		t.Error("unexpected non-nil instance")
  3221  	}
  3222  }
  3223  
  3224  func TestPos(t *testing.T) {
  3225  	testCases := []struct {
  3226  		value string
  3227  		pos   string
  3228  		skip  bool
  3229  	}{{
  3230  		value: `
  3231  a: string
  3232  a: "foo"`,
  3233  		pos: "3:4",
  3234  	}, {
  3235  		value: `
  3236  a: x: string
  3237  a: x: "x"`,
  3238  		pos: "2:4",
  3239  
  3240  		// the position of the new evaluator is also correct, and actually
  3241  		// better.
  3242  		skip: true,
  3243  	}, {
  3244  		// Prefer struct conjuncts with actual fields.
  3245  		value: `
  3246  a: [string]: string
  3247  a: x: "x"`,
  3248  		pos: "3:4",
  3249  	}, {
  3250  		value: `
  3251  a: [string]: [string]: string
  3252  a: x: y: "x"`,
  3253  		pos: "3:4",
  3254  	}, {
  3255  		value: `
  3256  a: [string]: [string]: [string]: string
  3257  a: x: y: z: "x"`,
  3258  		pos: "3:4",
  3259  	}}
  3260  	for _, tc := range testCases {
  3261  		cuetdtest.FullMatrix.Run(t, "", func(t *cuetdtest.M) {
  3262  			if tc.skip {
  3263  				t.TODO_V3()
  3264  			}
  3265  
  3266  			c := t.Context()
  3267  			v := c.CompileString(tc.value)
  3268  			v = v.LookupPath(cue.ParsePath("a"))
  3269  			pos := v.Pos().String()
  3270  			if pos != tc.pos {
  3271  				t.Errorf("got %v; want %v", pos, tc.pos)
  3272  			}
  3273  		})
  3274  	}
  3275  }
  3276  
  3277  func TestPathCorrection(t *testing.T) {
  3278  	testCases := []struct {
  3279  		input  string
  3280  		lookup func(i cue.Value) cue.Value
  3281  		want   string
  3282  		skip   bool
  3283  	}{{
  3284  		input: `
  3285  			a: b: {
  3286  				c: d: b
  3287  			}
  3288  			`,
  3289  		lookup: func(i cue.Value) cue.Value {
  3290  			op, a := i.Lookup("a", "b", "c", "d").Expr()
  3291  			_ = op
  3292  			return a[0] // structural cycle errors.
  3293  		},
  3294  		want: "a",
  3295  	}, {
  3296  
  3297  		// TODO: embedding: have field operators.
  3298  		input: `
  3299  			a: {
  3300  				{x: c}
  3301  				c: 3
  3302  			}
  3303  			`,
  3304  		lookup: func(i cue.Value) cue.Value {
  3305  			op, a := i.Lookup("a").Expr()
  3306  			_ = op
  3307  			return a[0].Lookup("x")
  3308  		},
  3309  		want: "a.c",
  3310  	}, {
  3311  
  3312  		// TODO: implement proper Elem()
  3313  		input: `
  3314  			a: b: [...T]
  3315  			a: b: [...T]
  3316  			T: int
  3317  			`,
  3318  		lookup: func(i cue.Value) cue.Value {
  3319  			v, _ := i.Lookup("a", "b").Elem()
  3320  			_, a := v.Expr()
  3321  			return a[0]
  3322  		},
  3323  		want: "T",
  3324  	}, {
  3325  		input: `
  3326  				#S: {
  3327  					b?: [...#T]
  3328  					b?: [...#T]
  3329  				}
  3330  				#T: int
  3331  				`,
  3332  		lookup: func(i cue.Value) cue.Value {
  3333  			v := i.LookupDef("#S")
  3334  			f, _ := v.LookupField("b")
  3335  			v, _ = f.Value.Elem()
  3336  			_, a := v.Expr()
  3337  			return a[0]
  3338  		},
  3339  		want: "#T",
  3340  	}, {
  3341  		input: `
  3342  		#S: {
  3343  			a?: [...#T]
  3344  			b?: [...#T]
  3345  		}
  3346  		#T: int
  3347  		`,
  3348  		lookup: func(i cue.Value) cue.Value {
  3349  			v := i.LookupDef("#S")
  3350  			f, _ := v.LookupField("a")
  3351  			x := f.Value
  3352  			f, _ = v.LookupField("b")
  3353  			y := f.Value
  3354  			u := x.Unify(y)
  3355  			v, _ = u.Elem()
  3356  			_, a := v.Expr()
  3357  			return a[0]
  3358  		},
  3359  		want: "#T",
  3360  	}, {
  3361  		input: `
  3362  		#a: {
  3363  			close({}) | close({c: #T}) | close({d: string})
  3364  			#T: {b: 3}
  3365  		}
  3366  		`,
  3367  		lookup: func(i cue.Value) cue.Value {
  3368  			f, _ := i.LookupField("#a")
  3369  			_, a := f.Value.Expr() // &
  3370  			_, a = a[0].Expr()     // |
  3371  			return a[1].Lookup("c")
  3372  		},
  3373  		want: "#a.#T",
  3374  	}, {
  3375  		input: `
  3376  		package foo
  3377  
  3378  		#Struct: {
  3379  			#T: int
  3380  
  3381  			{b?: #T}
  3382  		}`,
  3383  		want: "#Struct.#T",
  3384  		lookup: func(val cue.Value) cue.Value {
  3385  			// Locate Struct
  3386  			i, _ := val.Fields(cue.Definitions(true))
  3387  			if !i.Next() {
  3388  				t.Fatal("no fields")
  3389  			}
  3390  			// Locate b
  3391  			i, _ = i.Value().Fields(cue.Definitions(true), cue.Optional(true))
  3392  			if !(i.Next() && i.Next()) {
  3393  				t.Fatal("no fields")
  3394  			}
  3395  			v := i.Value()
  3396  			return v
  3397  		},
  3398  	}, {
  3399  
  3400  		input: `
  3401  		package foo
  3402  
  3403  		#A: #B: #T
  3404  
  3405  		#T: {
  3406  			a: #S.#U
  3407  			#S: #U: {}
  3408  		}
  3409  		`,
  3410  		want: "#T.#S.#U",
  3411  		lookup: func(val cue.Value) cue.Value {
  3412  			f, _ := val.LookupField("#A")
  3413  			f, _ = f.Value.LookupField("#B")
  3414  			v := f.Value
  3415  			v = cue.Dereference(v)
  3416  			v = v.Lookup("a")
  3417  			return v
  3418  		},
  3419  	}, {
  3420  
  3421  		// TODO: record additionalItems in list
  3422  		input: `
  3423  			package foo
  3424  
  3425  			#A: #B: #T
  3426  
  3427  			#T: {
  3428  				a: [...#S]
  3429  				#S: {}
  3430  			}
  3431  			`,
  3432  		want: "#T.#S",
  3433  		lookup: func(val cue.Value) cue.Value {
  3434  			f, _ := val.LookupField("#A")
  3435  			f, _ = f.Value.LookupField("#B")
  3436  			v := f.Value
  3437  			v = cue.Dereference(v)
  3438  			v, _ = v.Lookup("a").Elem()
  3439  			return v
  3440  		},
  3441  	}, {
  3442  		input: `
  3443  		#A: {
  3444  			b: #T
  3445  		}
  3446  
  3447  		#T: {
  3448  			a: #S
  3449  			#S: {}
  3450  		}
  3451  		`,
  3452  		want: "#T.#S",
  3453  		lookup: func(val cue.Value) cue.Value {
  3454  			f, _ := val.LookupField("#A")
  3455  			v := f.Value.Lookup("b")
  3456  			v = cue.Dereference(v)
  3457  			v = v.Lookup("a")
  3458  			return v
  3459  		},
  3460  	}, {
  3461  		input: `
  3462  			#Tracing: {
  3463  				#T: { address?: string }
  3464  				#S: { ip?: string }
  3465  
  3466  				close({}) | close({
  3467  					t: #T
  3468  				}) | close({
  3469  					s: #S
  3470  				})
  3471  			}
  3472  			#X: {}
  3473  			#X // Disconnect top-level struct from the one visible by close.
  3474  			`,
  3475  		want: "#Tracing.#T",
  3476  		lookup: func(val cue.Value) cue.Value {
  3477  			f, _ := val.LookupField("#Tracing")
  3478  			v := f.Value.Eval()
  3479  			_, args := v.Expr()
  3480  			v = args[1]
  3481  			v = v.Lookup("t")
  3482  			return v
  3483  		},
  3484  	}, {
  3485  		input: `
  3486  		x: { if true { v: a } }
  3487  		a: b
  3488  		b: 2
  3489  		`,
  3490  		want: "b",
  3491  		lookup: func(val cue.Value) cue.Value {
  3492  			v := val.LookupPath(cue.ParsePath("x.v"))
  3493  			v = cue.Dereference(v)
  3494  			return v
  3495  		},
  3496  	}, {
  3497  		input: `
  3498  		package foo
  3499  
  3500  		#A:{ if true { #B: #T } }
  3501  
  3502  		#T: {
  3503  			a: #S.#U
  3504  			#S: #U: {}
  3505  		}
  3506  		`,
  3507  		want: "#T.#S.#U",
  3508  		lookup: func(val cue.Value) cue.Value {
  3509  			f, _ := val.LookupField("#A")
  3510  			f, _ = f.Value.LookupField("#B")
  3511  			v := f.Value
  3512  			v = cue.Dereference(v)
  3513  			v = v.Lookup("a")
  3514  			return v
  3515  		},
  3516  	}}
  3517  	for _, tc := range testCases {
  3518  		if tc.skip {
  3519  			continue
  3520  		}
  3521  		cuetdtest.FullMatrix.Run(t, "", func(t *cuetdtest.M) {
  3522  			ctx := t.Context()
  3523  
  3524  			// don't use mustCompile because some test cases here need to
  3525  			// inspect the value error.
  3526  			val := ctx.CompileString(tc.input, cue.Filename("in"))
  3527  			v := tc.lookup(val)
  3528  			gotVal, ref := v.ReferencePath()
  3529  			if gotVal != val {
  3530  				t.Error("reference not in original instance")
  3531  			}
  3532  			gotPath := strings.Join(cue.PathToStrings(ref), ".")
  3533  			if gotPath != tc.want {
  3534  				t.Errorf("got path %s; want %s", gotPath, tc.want)
  3535  			}
  3536  
  3537  			x, p := v.ReferencePath()
  3538  			if x != val {
  3539  				t.Error("reference not in original instance")
  3540  			}
  3541  			gotPath = p.String()
  3542  			if gotPath != tc.want {
  3543  				t.Errorf("got path %s; want %s", gotPath, tc.want)
  3544  			}
  3545  
  3546  		})
  3547  	}
  3548  }
  3549  
  3550  // func TestReferences(t *testing.T) {
  3551  // 	config1 := `
  3552  // 	a: {
  3553  // 		b: 3
  3554  // 	}
  3555  // 	c: {
  3556  // 		d: a.b
  3557  // 		e: c.d
  3558  // 		f: a
  3559  // 	}
  3560  // 	`
  3561  // 	config2 := `
  3562  // 	a: { c: 3 }
  3563  // 	b: { c: int, d: 4 }
  3564  // 	r: (a & b).c
  3565  // 	c: {args: s1 + s2}.args
  3566  // 	s1: string
  3567  // 	s2: string
  3568  // 	d: ({arg: b}).arg.c
  3569  // 	e: f.arg.c
  3570  // 	f: {arg: b}
  3571  // 	`
  3572  // 	testCases := []struct {
  3573  // 		config string
  3574  // 		in     string
  3575  // 		out    string
  3576  // 	}{
  3577  // 		{config1, "c.d", "a.b"},
  3578  // 		{config1, "c.e", "c.d"},
  3579  // 		{config1, "c.f", "a"},
  3580  
  3581  // 		{config2, "r", "a.c b.c"},
  3582  // 		{config2, "c", "s1 s2"},
  3583  // 		// {config2, "d", "b.c"}, // TODO: make this work as well.
  3584  // 		{config2, "e", "f.arg.c"}, // TODO: should also report b.c.
  3585  // 	}
  3586  // 	for _, tc := range testCases {
  3587  // 		t.Run(tc.in, func(t *testing.T) {
  3588  // 			ctx, st := compileFile(t, tc.config)
  3589  // 			v := newValueRoot(ctx, st)
  3590  // 			for _, k := range strings.Split(tc.in, ".") {
  3591  // 				obj, err := v.structValFull(ctx)
  3592  // 				if err != nil {
  3593  // 					t.Fatal(err)
  3594  // 				}
  3595  // 				v = obj.Lookup(k)
  3596  // 			}
  3597  // 			got := []string{}
  3598  // 			for _, r := range v.References() {
  3599  // 				got = append(got, strings.Join(r, "."))
  3600  // 			}
  3601  // 			want := strings.Split(tc.out, " ")
  3602  // 			if !reflect.DeepEqual(got, want) {
  3603  // 				t.Errorf("got %v; want %v", got, want)
  3604  // 			}
  3605  // 		})
  3606  // 	}
  3607  // }
  3608  
  3609  func checkErr(t *testing.T, err error, str, name string) bool {
  3610  	t.Helper()
  3611  	if err == nil {
  3612  		if str != "" {
  3613  			t.Errorf(`err:%s: got ""; want %q`, name, str)
  3614  		}
  3615  		return true
  3616  	}
  3617  	return checkFailed(t, err, str, name)
  3618  }
  3619  
  3620  func checkFatal(t *testing.T, err error, str, name string) {
  3621  	t.Helper()
  3622  	if !checkFailed(t, err, str, name) {
  3623  		t.SkipNow()
  3624  	}
  3625  }
  3626  
  3627  func checkFailed(t *testing.T, err error, str, name string) bool {
  3628  	t.Helper()
  3629  	if err != nil {
  3630  		got := err.Error()
  3631  		if str == "" {
  3632  			t.Fatalf(`err:%s: got %q; want ""`, name, got)
  3633  		}
  3634  		if !strings.Contains(got, str) {
  3635  			t.Errorf(`err:%s: got %q; want %q`, name, got, str)
  3636  		}
  3637  		return false
  3638  	}
  3639  	return true
  3640  }
  3641  
  3642  func TestExpr(t *testing.T) {
  3643  	testCases := []struct {
  3644  		input string
  3645  		want  string
  3646  	}{{
  3647  		input: "v: 3",
  3648  		want:  "3",
  3649  	}, {
  3650  		input: "v: 3 + 4",
  3651  		want:  "+(3 4)",
  3652  	}, {
  3653  		input: "v: !a, a: bool",
  3654  		want:  `!(.(〈〉 "a"))`,
  3655  	}, {
  3656  		input: "v: !a, a: 3", // TODO: Should still look up.
  3657  		want:  `!(.(〈〉 "a"))`,
  3658  	}, {
  3659  		input: "v: 1 | 2 | 3 | *4",
  3660  		want:  "|(1 2 3 4)",
  3661  	}, {
  3662  		input: "v: 2 & 5", // Allow even with error.
  3663  		want:  "&(2 5)",
  3664  	}, {
  3665  		input: "v: 2 | 5",
  3666  		want:  "|(2 5)",
  3667  	}, {
  3668  		input: "v: 2 && 5",
  3669  		want:  "&&(2 5)",
  3670  	}, {
  3671  		input: "v: 2 || 5",
  3672  		want:  "||(2 5)",
  3673  	}, {
  3674  		input: "v: 2 == 5",
  3675  		want:  "==(2 5)",
  3676  	}, {
  3677  		input: "v: !b, b: true",
  3678  		want:  `!(.(〈〉 "b"))`,
  3679  	}, {
  3680  		input: "v: 2 != 5",
  3681  		want:  "!=(2 5)",
  3682  	}, {
  3683  		input: "v: <5",
  3684  		want:  "<(5)",
  3685  	}, {
  3686  		input: "v: 2 <= 5",
  3687  		want:  "<=(2 5)",
  3688  	}, {
  3689  		input: "v: 2 > 5",
  3690  		want:  ">(2 5)",
  3691  	}, {
  3692  		input: "v: 2 >= 5",
  3693  		want:  ">=(2 5)",
  3694  	}, {
  3695  		input: "v: 2 =~ 5",
  3696  		want:  "=~(2 5)",
  3697  	}, {
  3698  		input: "v: 2 !~ 5",
  3699  		want:  "!~(2 5)",
  3700  	}, {
  3701  		input: "v: 2 + 5",
  3702  		want:  "+(2 5)",
  3703  	}, {
  3704  		input: "v: 2 - 5",
  3705  		want:  "-(2 5)",
  3706  	}, {
  3707  		input: "v: 2 * 5",
  3708  		want:  "*(2 5)",
  3709  	}, {
  3710  		input: "v: 2 / 5",
  3711  		want:  "/(2 5)",
  3712  	}, {
  3713  		input: "v: 2 quo 5",
  3714  		want:  "quo(2 5)",
  3715  	}, {
  3716  		input: "v: 2 rem 5",
  3717  		want:  "rem(2 5)",
  3718  	}, {
  3719  		input: "v: 2 div 5",
  3720  		want:  "div(2 5)",
  3721  	}, {
  3722  		input: "v: 2 mod 5",
  3723  		want:  "mod(2 5)",
  3724  	}, {
  3725  		input: "v: a.b, a: b: 4",
  3726  		want:  `.(.(〈〉 "a") "b")`,
  3727  	}, {
  3728  		input: `v: a["b"], a: b: 3 `,
  3729  		want:  `[](.(〈〉 "a") "b")`,
  3730  	}, {
  3731  		input: "v: a[2:5], a: [1, 2, 3, 4, 5]",
  3732  		want:  `[:](.(〈〉 "a") 2 5)`,
  3733  	}, {
  3734  		input: "v: len([])",
  3735  		want:  "()(len [])",
  3736  	}, {
  3737  		input: "v: a.b, a: { b: string }",
  3738  		want:  `.(.(〈〉 "a") "b")`,
  3739  	}, {
  3740  		input: `v: "Hello, \(x)! Welcome to \(place)", place: string, x: string`,
  3741  		want:  `\()("Hello, " .(〈〉 "x") "! Welcome to " .(〈〉 "place") "")`,
  3742  	}, {
  3743  		// Split out the reference, but ensure the split-off outer struct
  3744  		// remains valid.
  3745  		input: `v: { a, #b: 1 }, a: 2`,
  3746  		want:  `&(.(〈〉 "a") {int,#b:1})`,
  3747  	}, {
  3748  		// Result is an error, no need to split off.
  3749  		input: `v: { a, b: 1 }, a: 2`,
  3750  		want:  `&(.(〈〉 "a") {b:1})`,
  3751  	}, {
  3752  		// Don't split of concrete values.
  3753  		input: `v: { "foo", #def: 1 }`,
  3754  		want:  `{"foo",#def:1}`,
  3755  	}, {
  3756  		input: `v: { {} | { a: #A, b: #B}, #A: {} | { c: int} }, #B: int | bool`,
  3757  		want:  `&(|({} {a:#A,b:#B}) {#A:({}|{c:int})})`,
  3758  	}, {
  3759  		input: `v: { {c: a}, b: a }, a: int`,
  3760  		want:  `&({c:a} {b:a})`,
  3761  	}, {
  3762  		input: `v: [...number] | *[1, 2, 3]`,
  3763  		// Filter defaults that are subsumed by another value.
  3764  		want: `[...number]`,
  3765  	}, {
  3766  		input: `v: or([1, 2, 3])`,
  3767  		want:  `|(1 2 3)`,
  3768  	}, {
  3769  		input: `v: or([])`,
  3770  		want:  `_|_(empty list in call to or)`,
  3771  	}, {
  3772  		input: `v: and([1, 2, 3])`,
  3773  		want:  `&(1 2 3)`,
  3774  	}, {
  3775  		input: `v: and([])`,
  3776  		want:  `_`,
  3777  	}, {
  3778  		//Issue #1245
  3779  		input: `
  3780  				x: *4 | int
  3781  				v: x | *7
  3782  				`,
  3783  		want: `|(.(〈〉 "x") 7)`,
  3784  	}, {
  3785  		// Issue #1119
  3786  		// Unwrap single embedded values.
  3787  		input: `v: {>30}`,
  3788  		want:  `>(30)`,
  3789  	}, {
  3790  		input: `v: {>30, <40}`,
  3791  		want:  `&(>(30) <(40))`,
  3792  	}, {
  3793  		input: `a: string, if true { v: a }`,
  3794  		want:  `.(〈〉 "a")`,
  3795  	}}
  3796  	for _, tc := range testCases {
  3797  		cuetdtest.FullMatrix.Run(t, tc.input, func(t *cuetdtest.M) {
  3798  			v := getValue(t, tc.input).Lookup("v")
  3799  			got := exprStr(v)
  3800  			if got != tc.want {
  3801  				t.Errorf("\n got %v;\nwant %v", got, tc.want)
  3802  			}
  3803  		})
  3804  	}
  3805  }
  3806  
  3807  func exprStr(v cue.Value) string {
  3808  	op, operands := v.Expr()
  3809  	if op == cue.NoOp {
  3810  		return compactRawStr(operands[0])
  3811  	}
  3812  	s := op.String()
  3813  	s += "("
  3814  	for i, v := range operands {
  3815  		if i > 0 {
  3816  			s += " "
  3817  		}
  3818  		s += exprStr(v)
  3819  	}
  3820  	s += ")"
  3821  	return s
  3822  }
  3823  
  3824  func compactRawStr(v cue.Value) string {
  3825  	ctx := cue.ValueCtx(v)
  3826  	cfg := &debug.Config{Compact: true, Raw: true}
  3827  	return debug.NodeString(ctx, cue.ValueVertex(v), cfg)
  3828  }