...

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

Documentation: cuelang.org/go/cue

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

View as plain text