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