Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 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 | |
Marcel van Lohuizen | 311f5bc | 2020-07-07 15:58:16 +0200 | [diff] [blame] | 15 | package export_test |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 16 | |
| 17 | import ( |
| 18 | "flag" |
| 19 | "testing" |
| 20 | |
Marcel van Lohuizen | 845df05 | 2020-07-26 13:15:45 +0200 | [diff] [blame] | 21 | "cuelang.org/go/cue" |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 22 | "cuelang.org/go/cue/ast" |
| 23 | "cuelang.org/go/cue/errors" |
| 24 | "cuelang.org/go/cue/format" |
Marcel van Lohuizen | 1e1fe6f | 2020-09-17 13:34:29 +0200 | [diff] [blame] | 25 | "cuelang.org/go/cue/parser" |
Marcel van Lohuizen | f0df4df | 2020-09-18 17:52:03 +0200 | [diff] [blame] | 26 | "cuelang.org/go/encoding/gocode/gocodec" |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 27 | "cuelang.org/go/internal" |
| 28 | "cuelang.org/go/internal/core/adt" |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 29 | "cuelang.org/go/internal/core/compile" |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 30 | "cuelang.org/go/internal/core/convert" |
Marcel van Lohuizen | 18736bf | 2020-07-15 17:02:42 +0200 | [diff] [blame] | 31 | "cuelang.org/go/internal/core/eval" |
Marcel van Lohuizen | 311f5bc | 2020-07-07 15:58:16 +0200 | [diff] [blame] | 32 | "cuelang.org/go/internal/core/export" |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 33 | "cuelang.org/go/internal/core/runtime" |
| 34 | "cuelang.org/go/internal/cuetxtar" |
| 35 | "github.com/rogpeppe/go-internal/txtar" |
| 36 | ) |
| 37 | |
| 38 | var update = flag.Bool("update", false, "update the test files") |
| 39 | |
| 40 | func TestDefinition(t *testing.T) { |
| 41 | test := cuetxtar.TxTarTest{ |
| 42 | Root: "./testdata", |
| 43 | Name: "definition", |
| 44 | Update: *update, |
| 45 | } |
| 46 | |
Marcel van Lohuizen | 311f5bc | 2020-07-07 15:58:16 +0200 | [diff] [blame] | 47 | r := cue.NewRuntime() |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 48 | |
| 49 | test.Run(t, func(t *cuetxtar.Test) { |
| 50 | a := t.ValidInstances() |
| 51 | |
| 52 | v, errs := compile.Files(nil, r, a[0].Files...) |
| 53 | if errs != nil { |
| 54 | t.Fatal(errs) |
| 55 | } |
Marcel van Lohuizen | 18736bf | 2020-07-15 17:02:42 +0200 | [diff] [blame] | 56 | v.Finalize(eval.NewContext(r, v)) |
| 57 | |
| 58 | // TODO: do we need to evaluate v? In principle not necessary. |
| 59 | // v.Finalize(eval.NewContext(r, v)) |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 60 | |
Marcel van Lohuizen | 311f5bc | 2020-07-07 15:58:16 +0200 | [diff] [blame] | 61 | file, errs := export.Def(r, v) |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 62 | errors.Print(t, errs, nil) |
| 63 | _, _ = t.Write(formatNode(t.T, file)) |
| 64 | }) |
| 65 | } |
| 66 | |
| 67 | func formatNode(t *testing.T, n ast.Node) []byte { |
| 68 | t.Helper() |
| 69 | |
| 70 | b, err := format.Node(n) |
| 71 | if err != nil { |
| 72 | t.Fatal(err) |
| 73 | } |
| 74 | return b |
| 75 | } |
| 76 | |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 77 | // TestGenerated tests conversions of generated Go structs, which may be |
| 78 | // different from parsed or evaluated CUE, such as having Vertex values. |
| 79 | func TestGenerated(t *testing.T) { |
| 80 | testCases := []struct { |
Marcel van Lohuizen | 1e1fe6f | 2020-09-17 13:34:29 +0200 | [diff] [blame] | 81 | in func(ctx *adt.OpContext) (adt.Expr, error) |
| 82 | out string |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 83 | }{{ |
Marcel van Lohuizen | 1e1fe6f | 2020-09-17 13:34:29 +0200 | [diff] [blame] | 84 | in: func(ctx *adt.OpContext) (adt.Expr, error) { |
| 85 | in := &C{ |
| 86 | Terminals: []*A{{Name: "Name", Description: "Desc"}}, |
| 87 | } |
| 88 | return convert.GoValueToValue(ctx, in, false), nil |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 89 | }, |
Marcel van Lohuizen | 1e1fe6f | 2020-09-17 13:34:29 +0200 | [diff] [blame] | 90 | out: `{Terminals: [{Description: "Desc", Name: "Name"}]}`, |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 91 | }, { |
Marcel van Lohuizen | 1e1fe6f | 2020-09-17 13:34:29 +0200 | [diff] [blame] | 92 | in: func(ctx *adt.OpContext) (adt.Expr, error) { |
| 93 | in := &C{ |
| 94 | Terminals: []*A{{Name: "Name", Description: "Desc"}}, |
| 95 | } |
| 96 | return convert.GoTypeToExpr(ctx, in) |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 97 | }, |
Marcel van Lohuizen | 1e1fe6f | 2020-09-17 13:34:29 +0200 | [diff] [blame] | 98 | out: `*null|{Terminals?: *null|[...*null|{Name: string, Description: string}]}`, |
| 99 | }, { |
| 100 | in: func(ctx *adt.OpContext) (adt.Expr, error) { |
| 101 | in := []*A{{Name: "Name", Description: "Desc"}} |
| 102 | return convert.GoValueToValue(ctx, in, false), nil |
| 103 | }, |
| 104 | out: `[{Name: "Name", Description: "Desc"}]`, |
| 105 | }, { |
| 106 | in: func(ctx *adt.OpContext) (adt.Expr, error) { |
| 107 | in := []*A{{Name: "Name", Description: "Desc"}} |
| 108 | return convert.GoTypeToExpr(ctx, in) |
| 109 | }, |
| 110 | out: `*null|[...*null|{Name: string, Description: string}]`, |
| 111 | }, { |
| 112 | in: func(ctx *adt.OpContext) (adt.Expr, error) { |
| 113 | expr, err := parser.ParseExpr("test", `{ |
| 114 | x: Guide.#Terminal |
| 115 | Guide: {} |
| 116 | }`) |
| 117 | if err != nil { |
| 118 | return nil, err |
| 119 | } |
| 120 | c, err := compile.Expr(nil, ctx, expr) |
| 121 | if err != nil { |
| 122 | return nil, err |
| 123 | } |
| 124 | root := &adt.Vertex{} |
| 125 | root.AddConjunct(c) |
| 126 | root.Finalize(ctx) |
| 127 | |
| 128 | // Simulate Value.Unify of Lookup("x") and Lookup("Guide"). |
| 129 | n := &adt.Vertex{} |
| 130 | n.AddConjunct(adt.MakeRootConjunct(nil, root.Arcs[0])) |
| 131 | n.AddConjunct(adt.MakeRootConjunct(nil, root.Arcs[1])) |
| 132 | n.Finalize(ctx) |
| 133 | |
| 134 | return n, nil |
| 135 | }, |
| 136 | out: `<[l2// x: undefined field #Terminal] _|_>`, |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 137 | }} |
| 138 | for _, tc := range testCases { |
| 139 | t.Run("", func(t *testing.T) { |
| 140 | r := runtime.New() |
| 141 | e := eval.New(r) |
| 142 | ctx := adt.NewContext(r, e, &adt.Vertex{}) |
| 143 | |
Marcel van Lohuizen | 1e1fe6f | 2020-09-17 13:34:29 +0200 | [diff] [blame] | 144 | v, err := tc.in(ctx) |
| 145 | if err != nil { |
| 146 | t.Fatal("failed test case: ", err) |
| 147 | } |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 148 | expr, err := export.Expr(ctx, v) |
| 149 | if err != nil { |
Marcel van Lohuizen | 1e1fe6f | 2020-09-17 13:34:29 +0200 | [diff] [blame] | 150 | t.Fatal("failed export: ", err) |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 151 | } |
| 152 | got := internal.DebugStr(expr) |
Marcel van Lohuizen | 1e1fe6f | 2020-09-17 13:34:29 +0200 | [diff] [blame] | 153 | if got != tc.out { |
| 154 | t.Errorf("got: %s\nwant: %s", got, tc.out) |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 155 | } |
Marcel van Lohuizen | b9b2c54 | 2020-09-16 21:24:03 +0200 | [diff] [blame] | 156 | }) |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | type A struct { |
| 161 | Name string |
| 162 | Description string |
| 163 | } |
| 164 | |
| 165 | type B struct { |
| 166 | Image string |
| 167 | } |
| 168 | |
| 169 | type C struct { |
| 170 | Terminals []*A |
| 171 | } |
| 172 | |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 173 | // For debugging purposes. Do not delete. |
| 174 | func TestX(t *testing.T) { |
| 175 | t.Skip() |
| 176 | |
| 177 | in := ` |
| 178 | -- in.cue -- |
| 179 | package test |
| 180 | |
Marcel van Lohuizen | 18736bf | 2020-07-15 17:02:42 +0200 | [diff] [blame] | 181 | // // Foo |
| 182 | // a: [X=string]: [Y=string]: { |
| 183 | // name: X+Y |
| 184 | // } |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 185 | |
Marcel van Lohuizen | 18736bf | 2020-07-15 17:02:42 +0200 | [diff] [blame] | 186 | // [Y=string]: [X=string]: name: {Y+X} |
| 187 | // { |
| 188 | // name: X.other + Y |
| 189 | // other: string |
| 190 | // } |
| 191 | |
| 192 | // c: [X=string]: X |
| 193 | |
| 194 | // #pkg1: Object |
| 195 | |
| 196 | // "Hello \(#pkg1)!" |
| 197 | |
| 198 | |
| 199 | // Object: "World" |
| 200 | |
| 201 | // // A Foo fooses stuff. |
| 202 | // foos are instances of Foo. |
| 203 | // foos: [string]: {} |
| 204 | |
| 205 | // // // My first little foo. |
| 206 | // foos: MyFoo: {} |
| 207 | |
| 208 | bar: 3 |
| 209 | d2: C="foo\(bar)": { |
| 210 | name: "xx" |
| 211 | foo: C.name |
| 212 | } |
| 213 | |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 214 | ` |
| 215 | |
| 216 | archive := txtar.Parse([]byte(in)) |
| 217 | a := cuetxtar.Load(archive, "/tmp/test") |
Marcel van Lohuizen | 18736bf | 2020-07-15 17:02:42 +0200 | [diff] [blame] | 218 | if err := a[0].Err; err != nil { |
| 219 | t.Fatal(err) |
| 220 | } |
| 221 | |
| 222 | // x := a[0].Files[0] |
| 223 | // astutil.Sanitize(x) |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 224 | |
| 225 | r := runtime.New() |
| 226 | v, errs := compile.Files(nil, r, a[0].Files...) |
| 227 | if errs != nil { |
| 228 | t.Fatal(errs) |
| 229 | } |
Marcel van Lohuizen | 18736bf | 2020-07-15 17:02:42 +0200 | [diff] [blame] | 230 | v.Finalize(eval.NewContext(r, v)) |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 231 | |
Marcel van Lohuizen | 311f5bc | 2020-07-07 15:58:16 +0200 | [diff] [blame] | 232 | file, errs := export.Def(r, v) |
Marcel van Lohuizen | 0d12c33 | 2020-06-10 12:36:58 +0200 | [diff] [blame] | 233 | if errs != nil { |
| 234 | t.Fatal(errs) |
| 235 | } |
| 236 | |
| 237 | t.Error(string(formatNode(t, file))) |
| 238 | } |
Marcel van Lohuizen | f0df4df | 2020-09-18 17:52:03 +0200 | [diff] [blame] | 239 | |
| 240 | func TestFromGo(t *testing.T) { |
| 241 | type Struct struct { |
| 242 | A string |
| 243 | B string |
| 244 | } |
| 245 | |
| 246 | m := make(map[string]Struct) |
| 247 | m["hello"] = Struct{ |
| 248 | A: "a", |
| 249 | B: "b", |
| 250 | } |
| 251 | var r cue.Runtime |
| 252 | codec := gocodec.New(&r, nil) |
| 253 | v, err := codec.Decode(m) |
| 254 | if err != nil { |
| 255 | panic(err) |
| 256 | } |
| 257 | |
| 258 | syn, _ := format.Node(v.Syntax()) |
| 259 | if got := string(syn); got != `{ |
| 260 | hello: { |
| 261 | A: "a" |
| 262 | B: "b" |
| 263 | } |
| 264 | }` { |
| 265 | t.Errorf("incorrect ordering: %s\n", got) |
| 266 | } |
| 267 | } |