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