this repo has no description
at master 379 lines 9.0 kB view raw
1// Copyright 2020 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 15package export_test 16 17import ( 18 "testing" 19 20 "golang.org/x/tools/txtar" 21 22 "cuelang.org/go/cue" 23 "cuelang.org/go/cue/ast" 24 "cuelang.org/go/cue/cuecontext" 25 "cuelang.org/go/cue/errors" 26 "cuelang.org/go/cue/format" 27 "cuelang.org/go/cue/parser" 28 "cuelang.org/go/encoding/gocode/gocodec" 29 "cuelang.org/go/internal/astinternal" 30 "cuelang.org/go/internal/core/adt" 31 "cuelang.org/go/internal/core/compile" 32 "cuelang.org/go/internal/core/convert" 33 "cuelang.org/go/internal/core/eval" 34 "cuelang.org/go/internal/core/export" 35 "cuelang.org/go/internal/core/runtime" 36 "cuelang.org/go/internal/cuetdtest" 37 "cuelang.org/go/internal/cuetxtar" 38 "cuelang.org/go/internal/value" 39) 40 41func TestDefinition(t *testing.T) { 42 t.Parallel() 43 test := cuetxtar.TxTarTest{ 44 Root: "./testdata/main", 45 Name: "definition", 46 Matrix: cuetdtest.FullMatrix, 47 } 48 49 test.Run(t, func(t *cuetxtar.Test) { 50 r := t.Runtime() 51 a := t.Instance() 52 53 v, errs := compile.Files(nil, r, "", a.Files...) 54 if errs != nil { 55 t.Fatal(errs) 56 } 57 v.Finalize(eval.NewContext(r, v)) 58 59 file, errs := export.Def(r, "", v) 60 errors.Print(t, errs, nil) 61 _, _ = t.Write(formatNode(t.T, file)) 62 }) 63} 64 65func formatNode(t *testing.T, n ast.Node) []byte { 66 t.Helper() 67 68 b, err := format.Node(n) 69 if err != nil { 70 t.Fatal(err) 71 } 72 return b 73} 74 75// TestGenerated tests conversions of generated Go structs, which may be 76// different from parsed or evaluated CUE, such as having Vertex values. 77func TestGenerated(t *testing.T) { 78 cuetdtest.FullMatrix.Do(t, func(t *testing.T, m *cuetdtest.M) { 79 ctx := m.CueContext() 80 81 testCases := []struct { 82 in func(ctx *adt.OpContext) (adt.Expr, error) 83 out string 84 p *export.Profile 85 }{{ 86 in: func(ctx *adt.OpContext) (adt.Expr, error) { 87 in := &C{ 88 Terminals: []*A{{Name: "Name", Description: "Desc"}}, 89 } 90 return convert.FromGoValue(ctx, in, false), nil 91 }, 92 out: `Terminals: [{Name: "Name", Description: "Desc"}]`, 93 }, { 94 in: func(ctx *adt.OpContext) (adt.Expr, error) { 95 in := &C{ 96 Terminals: []*A{{Name: "Name", Description: "Desc"}}, 97 } 98 return convert.FromGoType(ctx, in) 99 }, 100 out: `*null|{Terminals?: *null|[...*null|{Name: string, Description: string}]}`, 101 }, { 102 in: func(ctx *adt.OpContext) (adt.Expr, error) { 103 in := []*A{{Name: "Name", Description: "Desc"}} 104 return convert.FromGoValue(ctx, in, false), nil 105 }, 106 out: `[{Name: "Name", Description: "Desc"}]`, 107 }, { 108 in: func(ctx *adt.OpContext) (adt.Expr, error) { 109 in := []*A{{Name: "Name", Description: "Desc"}} 110 return convert.FromGoType(ctx, in) 111 }, 112 out: `*null|[...*null|{Name: string, Description: string}]`, 113 }, { 114 in: func(ctx *adt.OpContext) (adt.Expr, error) { 115 in := &KeepGoFieldOrdering{} 116 return convert.FromGoValue(ctx, in, false), nil 117 }, 118 out: `One: 0, Two: 0, Three: 0, Four: 0, Five: 0, Six: 0, Seven: 0, Eight: 0, Nine: 0, Ten: 0`, 119 }, { 120 in: func(ctx *adt.OpContext) (adt.Expr, error) { 121 expr, err := parser.ParseExpr("test", `{ 122 x: Guide.#Terminal 123 Guide: {} 124 }`) 125 if err != nil { 126 return nil, err 127 } 128 c, err := compile.Expr(nil, ctx, "_", expr) 129 if err != nil { 130 return nil, err 131 } 132 root := &adt.Vertex{} 133 root.AddConjunct(c) 134 root.Finalize(ctx) 135 136 // Simulate Value.Unify of Lookup("x") and Lookup("Guide"). 137 n := &adt.Vertex{} 138 n.AddConjunct(adt.MakeRootConjunct(nil, root.Arcs[0])) 139 n.AddConjunct(adt.MakeRootConjunct(nil, root.Arcs[1])) 140 n.Finalize(ctx) 141 142 return n, nil 143 }, 144 out: `<[l2// x: undefined field: #Terminal] _|_>`, 145 p: export.Final, 146 }, { 147 in: func(r *adt.OpContext) (adt.Expr, error) { 148 v := ctx.CompileString(` 149 #Provider: { 150 ID: string 151 notConcrete: bool 152 a: int 153 b: a + 1 154 }`) 155 156 spec := v.LookupPath(cue.ParsePath("#Provider")) 157 spec2 := spec.FillPath(cue.ParsePath("ID"), "12345") 158 root := v.FillPath(cue.ParsePath("providers.foo"), spec2) 159 _, n := value.ToInternal(root) 160 161 return n, nil 162 }, 163 out: `#Provider: {ID: string, notConcrete: bool, a: int, b: a+1}, providers: {foo: {ID: "12345", notConcrete: bool, a: int, b: a+1}}`, 164 p: export.All, 165 }, { 166 // Issue #882 167 in: func(r *adt.OpContext) (adt.Expr, error) { 168 valA := ctx.CompileString(` 169 #One: { version: string } 170 `) 171 172 valB := ctx.CompileString(` 173 #One: _ 174 ones: {[string]: #One} 175 `) 176 v := valB.Unify(valA) 177 _, n := value.ToInternal(v) 178 return n, nil 179 }, 180 out: `#One: {version: string}, ones: {[string]: #One}`, 181 p: export.All, 182 }, { 183 // Indicate closedness in an element that is closed and misses parent 184 // context. 185 // Issue #882 186 in: func(r *adt.OpContext) (adt.Expr, error) { 187 v := ctx.CompileString(` 188 #A: b: c: string 189 `) 190 v = v.LookupPath(cue.ParsePath("#A.b")) 191 192 _, n := value.ToInternal(v) 193 return n, nil 194 }, 195 out: `_#def, _#def: {c: string}`, 196 p: export.All, 197 }, { 198 // Don't wrap in def if the if the value is an embedded scalar. 199 // Issue #977 200 in: func(r *adt.OpContext) (adt.Expr, error) { 201 v := ctx.CompileString(` 202 #A: { "foo", #enum: 2 } 203 `) 204 v = v.LookupPath(cue.ParsePath("#A")) 205 206 _, n := value.ToInternal(v) 207 return n, nil 208 }, 209 out: `"foo", #enum: 2`, 210 p: export.All, 211 }, { 212 // Issue #1131 213 in: func(r *adt.OpContext) (adt.Expr, error) { 214 m := make(map[string]interface{}) 215 v := ctx.Encode(m) 216 _, x := value.ToInternal(v) 217 return x, nil 218 }, 219 out: ``, // empty file 220 }, { 221 in: func(r *adt.OpContext) (adt.Expr, error) { 222 v := &adt.Vertex{} 223 v.SetValue(r, &adt.StructMarker{}) 224 return v, nil 225 }, 226 out: ``, // empty file 227 }} 228 for _, tc := range testCases { 229 t.Run("", func(t *testing.T) { 230 ctx := adt.NewContext((*runtime.Runtime)(ctx), &adt.Vertex{}) 231 v, err := tc.in(ctx) 232 if err != nil { 233 t.Fatal("failed test case: ", err) 234 } 235 236 p := tc.p 237 if p == nil { 238 p = export.Simplified 239 } 240 241 var n ast.Node 242 switch x := v.(type) { 243 case *adt.Vertex: 244 n, err = p.Def(ctx, "", x) 245 default: 246 n, err = p.Expr(ctx, "", v) 247 } 248 if err != nil { 249 t.Fatal("failed export: ", err) 250 } 251 got := astinternal.DebugStr(n) 252 if got != tc.out { 253 t.Errorf("got: %s\nwant: %s", got, tc.out) 254 } 255 }) 256 } 257 }) 258} 259 260type A struct { 261 Name string 262 Description string 263} 264 265type B struct { 266 Image string 267} 268 269type C struct { 270 Terminals []*A 271} 272 273type KeepGoFieldOrdering struct { 274 One, Two, Three, Four, Five int64 275 Six, Seven, Eight, Nine, Ten int32 276} 277 278// For debugging purposes. Do not delete. 279func TestX(t *testing.T) { 280 t.Skip() 281 282 in := ` 283-- in.cue -- 284 ` 285 286 archive := txtar.Parse([]byte(in)) 287 a := cuetxtar.Load(archive, t.TempDir()) 288 if err := a[0].Err; err != nil { 289 t.Fatal(err) 290 } 291 292 // x := a[0].Files[0] 293 // astutil.Sanitize(x) 294 295 ctx := cuecontext.New() 296 r := (*runtime.Runtime)(ctx) 297 v, errs := compile.Files(nil, r, "", a[0].Files...) 298 if errs != nil { 299 t.Fatal(errs) 300 } 301 v.Finalize(eval.NewContext(r, v)) 302 303 file, errs := export.Def(r, "main", v) 304 if errs != nil { 305 t.Fatal(errs) 306 } 307 308 t.Error(string(formatNode(t, file))) 309} 310 311func TestFromGo(t *testing.T) { 312 type Struct struct { 313 A string 314 B string 315 } 316 317 m := make(map[string]Struct) 318 m["hello"] = Struct{ 319 A: "a", 320 B: "b", 321 } 322 ctx := cuecontext.New() 323 codec := gocodec.New(ctx, nil) 324 v, err := codec.Decode(m) 325 if err != nil { 326 panic(err) 327 } 328 329 syn, _ := format.Node(v.Syntax()) 330 if got := string(syn); got != `{ 331 hello: { 332 A: "a" 333 B: "b" 334 } 335}` { 336 t.Errorf("incorrect ordering: %s\n", got) 337 } 338} 339 340func TestFromAPI(t *testing.T) { 341 testCases := []struct { 342 expr ast.Expr 343 out string 344 }{{ 345 expr: ast.NewCall(ast.NewIdent("close"), ast.NewStruct()), 346 out: `close({})`, 347 }, { 348 expr: ast.NewCall(ast.NewIdent("close"), ast.NewStruct( 349 "a", ast.NewString("foo"), 350 )), 351 out: `close({a: "foo"})`, 352 }, { 353 expr: ast.NewCall(ast.NewIdent("close"), ast.NewStruct( 354 ast.Embed(ast.NewStruct("a", ast.NewString("foo"))), 355 )), 356 out: `close({a: "foo"})`, 357 }} 358 // Issue #1204 359 for _, tc := range testCases { 360 cuetdtest.FullMatrix.Run(t, "", func(t *testing.T, m *cuetdtest.M) { 361 ctx := m.CueContext() 362 363 v := ctx.BuildExpr(tc.expr) 364 365 r, x := value.ToInternal(v) 366 file, err := export.Def(r, "foo", x) 367 368 if err != nil { 369 t.Fatal(err) 370 } 371 372 got := astinternal.DebugStr(file) 373 if got != tc.out { 374 t.Errorf("got: %s\nwant: %s", got, tc.out) 375 } 376 377 }) 378 } 379}