cuelang.org/go@v0.13.0/cue/syntax_test.go (about) 1 // Copyright 2021 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cue_test 16 17 import ( 18 "strings" 19 "testing" 20 21 "cuelang.org/go/cue" 22 "cuelang.org/go/cue/ast" 23 "cuelang.org/go/cue/cuecontext" 24 "cuelang.org/go/cue/format" 25 "cuelang.org/go/internal" 26 "cuelang.org/go/internal/core/runtime" 27 ) 28 29 func TestSyntax(t *testing.T) { 30 o := func(opts ...cue.Option) []cue.Option { 31 return opts 32 } 33 _ = o 34 testCases := []struct { 35 name string 36 in string 37 path string 38 options []cue.Option 39 out string 40 41 todoV3 bool 42 }{{ 43 name: "preseve docs", 44 in: ` 45 // Aloha 46 hello: "world" 47 // Aloha2 48 if true { 49 // Aloha3 50 if true { 51 // Aloha4 52 hello2: "world" 53 } 54 } 55 `, 56 options: o(cue.Docs(true)), 57 out: ` 58 { 59 // Aloha 60 hello: "world" 61 // Aloha2 62 if true { 63 // Aloha3 64 if true { 65 // Aloha4 66 hello2: "world" 67 } 68 } 69 }`, 70 }, { 71 name: "partially resolvable", 72 in: ` 73 x: {} 74 t: {name: string} 75 output: [ ... {t & x.value}] 76 `, 77 options: o(cue.ResolveReferences(true)), 78 out: ` 79 { 80 x: {} 81 t: { 82 name: string 83 } 84 output: [...t & x.value] 85 }`, 86 }, { 87 name: "issue867", 88 path: "output", 89 in: ` 90 x: {} 91 t: {name: string} 92 output: [ ... {t & x.value}] 93 `, 94 out: ` 95 { 96 [...T & {}.value] 97 98 //cue:path: t 99 let T = { 100 name: string 101 } 102 }`}, { 103 // Structural errors (and worse) are reported as is. 104 name: "structural error", 105 in: ` 106 #List: { 107 value: _ 108 next: #List 109 } 110 a: b: #List 111 `, 112 path: "a", 113 options: o(cue.ResolveReferences(true)), 114 out: ` 115 { 116 b: _|_ // #List.next: structural cycle (and 1 more errors) 117 }`, 118 // evalv3 seems to result in `b: {}`. 119 todoV3: true, 120 }, { 121 name: "resolveReferences", 122 path: "resource", 123 in: ` 124 // User 1 125 v1: #Deployment: { 126 spec: { 127 replicas: int 128 containers: [...] 129 other: option: int 130 } 131 132 incomplete: { 133 // NOTE: the definition of "a" will be out of scope so this 134 // reference will not be resolvable. 135 // TODO: hoist the definition of "a" into a let expression. 136 x: a.x 137 y: 1 | 2 138 z: [1, 2][a.x] 139 } 140 141 // NOTE: structural cycles are eliminated from disjunctions. This 142 // means the semantics of the type is not preserved. 143 // TODO: should we change this? 144 recursive: #List 145 } 146 147 a: {} 148 #D: {} 149 150 #List: { 151 Value: _ 152 Next: #List | *null 153 } 154 155 parameter: { 156 image: string 157 replicas: int 158 } 159 160 _mystring: string 161 162 resource: v1.#Deployment & { 163 spec: { 164 replicas: parameter.replicas 165 containers: [{ 166 image: parameter.image 167 name: "main" 168 envs: [..._mystring] 169 }] 170 } 171 } 172 173 parameter: image: *"myimage" | string 174 parameter: replicas: *2 | >=1 & <5 175 176 // User 2 177 parameter: replicas: int 178 179 resource: spec: replicas: parameter.replicas 180 181 parameter: replicas: 3 182 `, 183 options: o(cue.ResolveReferences(true)), 184 out: ` 185 { 186 spec: { 187 replicas: 3 188 containers: [{ 189 image: *"myimage" | string 190 name: "main" 191 envs: [...string] 192 }] 193 other: { 194 option: int 195 } 196 } 197 incomplete: { 198 x: {}.x 199 y: 1 | 2 200 z: [1, 2][{}.x] 201 } 202 recursive: { 203 Value: _ 204 Next: null 205 } 206 } 207 `, 208 }, { 209 name: "issue2339", 210 in: ` 211 s: string 212 if true { 213 out: "\(s)": 3 214 } 215 `, 216 options: o(cue.ResolveReferences(true)), 217 out: ` 218 { 219 s: string 220 out: { 221 "\(s)": 3 222 } 223 } 224 `, 225 }, { 226 name: "fragments", 227 in: ` 228 // #person is a real person 229 #person: { 230 children: [...#person] 231 name: =~"^[A-Za-z0-9]+$" 232 address: string 233 } 234 `, 235 path: "#person.children", 236 options: o(cue.Schema(), cue.Raw()), 237 out: `[...#person]`, 238 }} 239 for _, tc := range testCases { 240 t.Run(tc.name, func(t *testing.T) { 241 ctx := cuecontext.New() 242 if version, _ := (*runtime.Runtime)(ctx).Settings(); version == internal.EvalV3 && tc.todoV3 { 243 t.Skip("TODO: fix these tests on evalv3") 244 } 245 246 v := ctx.CompileString(tc.in) 247 v = v.LookupPath(cue.ParsePath(tc.path)) 248 249 syntax := v.Syntax(tc.options...) 250 b, err := format.Node(syntax) 251 if err != nil { 252 t.Fatal(err) 253 } 254 got := strings.TrimSpace(string(b)) 255 want := strings.TrimSpace(tc.out) 256 if got != want { 257 t.Errorf("got: %v; want %v", got, want) 258 } 259 }) 260 } 261 } 262 263 func TestFragment(t *testing.T) { 264 in := ` 265 #person: { 266 children: [...#person] 267 }` 268 269 ctx := cuecontext.New() 270 if version, _ := (*runtime.Runtime)(ctx).Settings(); version == internal.EvalV3 { 271 t.Skip("TODO: fix these tests on evalv3") 272 } 273 274 v := ctx.CompileString(in) 275 v = v.LookupPath(cue.ParsePath("#person.children")) 276 277 syntax := v.Syntax(cue.Schema(), cue.Raw()).(ast.Expr) 278 279 // Compile the fragment from within the scope it was derived. 280 v = ctx.BuildExpr(syntax, cue.Scope(v)) 281 282 // Generate the syntax, this time as self-contained. 283 syntax = v.Syntax(cue.Schema()).(ast.Expr) 284 b, err := format.Node(syntax) 285 if err != nil { 286 t.Fatal(err) 287 } 288 out := `{ 289 [...PERSON.#x] 290 291 //cue:path: #person 292 let PERSON = { 293 #x: { 294 children: [...#person] 295 } 296 } 297 }` 298 got := strings.TrimSpace(string(b)) 299 want := strings.TrimSpace(out) 300 if got != want { 301 t.Errorf("got: %v; want %v", got, want) 302 } 303 }